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
17package com.android.settings.print;
18
19import android.app.LoaderManager.LoaderCallbacks;
20import android.content.ActivityNotFoundException;
21import android.content.AsyncTaskLoader;
22import android.content.ComponentName;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.Loader;
27import android.content.pm.PackageManager;
28import android.content.pm.ResolveInfo;
29import android.database.ContentObserver;
30import android.graphics.drawable.Drawable;
31import android.net.Uri;
32import android.os.Bundle;
33import android.os.Handler;
34import android.os.Message;
35import android.os.UserHandle;
36import android.os.UserManager;
37import android.preference.Preference;
38import android.preference.PreferenceCategory;
39import android.preference.PreferenceScreen;
40import android.print.PrintJob;
41import android.print.PrintJobId;
42import android.print.PrintJobInfo;
43import android.print.PrintManager;
44import android.print.PrintManager.PrintJobStateChangeListener;
45import android.printservice.PrintServiceInfo;
46import android.provider.SearchIndexableResource;
47import android.provider.Settings;
48import android.text.TextUtils;
49import android.text.format.DateUtils;
50import android.util.Log;
51import android.view.View;
52import android.view.View.OnClickListener;
53import android.view.ViewGroup;
54import android.widget.AdapterView;
55import android.widget.AdapterView.OnItemSelectedListener;
56import android.widget.Button;
57import android.widget.Spinner;
58import android.widget.TextView;
59
60import com.android.internal.content.PackageMonitor;
61import com.android.internal.logging.MetricsLogger;
62import com.android.settings.DialogCreatable;
63import com.android.settings.R;
64import com.android.settings.SettingsPreferenceFragment;
65import com.android.settings.UserAdapter;
66import com.android.settings.Utils;
67import com.android.settings.search.BaseSearchIndexProvider;
68import com.android.settings.search.Indexable;
69import com.android.settings.search.SearchIndexableRaw;
70
71import java.text.DateFormat;
72import java.util.ArrayList;
73import java.util.List;
74
75/**
76 * Fragment with the top level print settings.
77 */
78public class PrintSettingsFragment extends SettingsPreferenceFragment
79        implements DialogCreatable, Indexable, OnItemSelectedListener, OnClickListener {
80    public static final String TAG = "PrintSettingsFragment";
81    private static final int LOADER_ID_PRINT_JOBS_LOADER = 1;
82
83    private static final String PRINT_JOBS_CATEGORY = "print_jobs_category";
84    private static final String PRINT_SERVICES_CATEGORY = "print_services_category";
85
86    // Extras passed to sub-fragments.
87    static final String EXTRA_PREFERENCE_KEY = "EXTRA_PREFERENCE_KEY";
88    static final String EXTRA_CHECKED = "EXTRA_CHECKED";
89    static final String EXTRA_TITLE = "EXTRA_TITLE";
90    static final String EXTRA_ENABLE_WARNING_TITLE = "EXTRA_ENABLE_WARNING_TITLE";
91    static final String EXTRA_ENABLE_WARNING_MESSAGE = "EXTRA_ENABLE_WARNING_MESSAGE";
92    static final String EXTRA_SETTINGS_TITLE = "EXTRA_SETTINGS_TITLE";
93    static final String EXTRA_SETTINGS_COMPONENT_NAME = "EXTRA_SETTINGS_COMPONENT_NAME";
94    static final String EXTRA_ADD_PRINTERS_TITLE = "EXTRA_ADD_PRINTERS_TITLE";
95    static final String EXTRA_ADD_PRINTERS_COMPONENT_NAME = "EXTRA_ADD_PRINTERS_COMPONENT_NAME";
96    static final String EXTRA_SERVICE_COMPONENT_NAME = "EXTRA_SERVICE_COMPONENT_NAME";
97
98    static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID";
99
100    private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME =
101            "EXTRA_PRINT_SERVICE_COMPONENT_NAME";
102
103    private static final int ORDER_LAST = 1000;
104
105    private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
106
107    private final Handler mHandler = new Handler() {
108        @Override
109        public void dispatchMessage(Message msg) {
110            updateServicesPreferences();
111        }
112    };
113
114    private final SettingsContentObserver mSettingsContentObserver =
115            new SettingsContentObserver(mHandler) {
116        @Override
117        public void onChange(boolean selfChange, Uri uri) {
118            updateServicesPreferences();
119        }
120    };
121
122    private PreferenceCategory mActivePrintJobsCategory;
123    private PreferenceCategory mPrintServicesCategory;
124
125    private PrintJobsController mPrintJobsController;
126    private UserAdapter mProfileSpinnerAdapter;
127    private Spinner mSpinner;
128    private Button mAddNewServiceButton;
129
130    @Override
131    protected int getMetricsCategory() {
132        return MetricsLogger.PRINT_SETTINGS;
133    }
134
135    @Override
136    protected int getHelpResource() {
137        return R.string.help_uri_printing;
138    }
139
140    @Override
141    public void onCreate(Bundle icicle) {
142        super.onCreate(icicle);
143        addPreferencesFromResource(R.xml.print_settings);
144
145        mActivePrintJobsCategory = (PreferenceCategory) findPreference(
146                PRINT_JOBS_CATEGORY);
147        mPrintServicesCategory = (PreferenceCategory) findPreference(
148                PRINT_SERVICES_CATEGORY);
149        getPreferenceScreen().removePreference(mActivePrintJobsCategory);
150
151        mPrintJobsController = new PrintJobsController();
152        getActivity().getLoaderManager().initLoader(LOADER_ID_PRINT_JOBS_LOADER,
153                null, mPrintJobsController);
154    }
155
156    @Override
157    public void onResume() {
158        super.onResume();
159        mSettingsPackageMonitor.register(getActivity(), getActivity().getMainLooper(), false);
160        mSettingsContentObserver.register(getContentResolver());
161        updateServicesPreferences();
162        setHasOptionsMenu(true);
163        startSubSettingsIfNeeded();
164    }
165
166    @Override
167    public void onPause() {
168        mSettingsPackageMonitor.unregister();
169        mSettingsContentObserver.unregister(getContentResolver());
170        super.onPause();
171    }
172
173    @Override
174    public void onViewCreated(View view, Bundle savedInstanceState) {
175        super.onViewCreated(view, savedInstanceState);
176        ViewGroup contentRoot = (ViewGroup) getListView().getParent();
177        View emptyView = getActivity().getLayoutInflater().inflate(
178                R.layout.empty_print_state, contentRoot, false);
179        TextView textView = (TextView) emptyView.findViewById(R.id.message);
180        textView.setText(R.string.print_no_services_installed);
181
182        final Intent addNewServiceIntent = createAddNewServiceIntentOrNull();
183        if (addNewServiceIntent != null) {
184            mAddNewServiceButton = (Button) emptyView.findViewById(R.id.add_new_service);
185            mAddNewServiceButton.setOnClickListener(this);
186            // The empty is used elsewhere too so it's hidden by default.
187            mAddNewServiceButton.setVisibility(View.VISIBLE);
188        }
189
190        contentRoot.addView(emptyView);
191        getListView().setEmptyView(emptyView);
192
193        final UserManager um = (UserManager) getSystemService(Context.USER_SERVICE);
194        mProfileSpinnerAdapter = Utils.createUserSpinnerAdapter(um, getActivity());
195        if (mProfileSpinnerAdapter != null) {
196            mSpinner = (Spinner) setPinnedHeaderView(R.layout.spinner_view);
197            mSpinner.setAdapter(mProfileSpinnerAdapter);
198            mSpinner.setOnItemSelectedListener(this);
199        }
200    }
201
202    private void updateServicesPreferences() {
203        if (getPreferenceScreen().findPreference(PRINT_SERVICES_CATEGORY) == null) {
204            getPreferenceScreen().addPreference(mPrintServicesCategory);
205        } else {
206            // Since services category is auto generated we have to do a pass
207            // to generate it since services can come and go.
208            mPrintServicesCategory.removeAll();
209        }
210
211        List<ComponentName> enabledServices = PrintSettingsUtils
212                .readEnabledPrintServices(getActivity());
213
214        final PackageManager pm = getActivity().getPackageManager();
215
216        List<ResolveInfo> installedServices = pm
217                .queryIntentServices(
218                        new Intent(android.printservice.PrintService.SERVICE_INTERFACE),
219                        PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
220
221        final int installedServiceCount = installedServices.size();
222        for (int i = 0; i < installedServiceCount; i++) {
223            ResolveInfo installedService = installedServices.get(i);
224
225            PreferenceScreen preference = getPreferenceManager().createPreferenceScreen(
226                    getActivity());
227
228            String title = installedService.loadLabel(getPackageManager()).toString();
229            preference.setTitle(title);
230
231            ComponentName componentName = new ComponentName(
232                    installedService.serviceInfo.packageName,
233                    installedService.serviceInfo.name);
234            preference.setKey(componentName.flattenToString());
235
236            preference.setOrder(i);
237            preference.setFragment(PrintServiceSettingsFragment.class.getName());
238            preference.setPersistent(false);
239
240            final boolean serviceEnabled = enabledServices.contains(componentName);
241            if (serviceEnabled) {
242                preference.setSummary(getString(R.string.print_feature_state_on));
243            } else {
244                preference.setSummary(getString(R.string.print_feature_state_off));
245            }
246
247            final Drawable drawable = installedService.loadIcon(pm);
248            if (drawable != null) {
249                preference.setIcon(drawable);
250            }
251
252            Bundle extras = preference.getExtras();
253            extras.putString(EXTRA_PREFERENCE_KEY, preference.getKey());
254            extras.putBoolean(EXTRA_CHECKED, serviceEnabled);
255            extras.putString(EXTRA_TITLE, title);
256
257            PrintServiceInfo printServiceInfo = PrintServiceInfo.create(
258                    installedService, getActivity());
259
260            CharSequence applicationLabel = installedService.loadLabel(getPackageManager());
261
262            extras.putString(EXTRA_ENABLE_WARNING_TITLE, getString(
263                    R.string.print_service_security_warning_title, applicationLabel));
264            extras.putString(EXTRA_ENABLE_WARNING_MESSAGE, getString(
265                    R.string.print_service_security_warning_summary, applicationLabel));
266
267            String settingsClassName = printServiceInfo.getSettingsActivityName();
268            if (!TextUtils.isEmpty(settingsClassName)) {
269                extras.putString(EXTRA_SETTINGS_TITLE,
270                        getString(R.string.print_menu_item_settings));
271                extras.putString(EXTRA_SETTINGS_COMPONENT_NAME,
272                        new ComponentName(installedService.serviceInfo.packageName,
273                                settingsClassName).flattenToString());
274            }
275
276            String addPrinterClassName = printServiceInfo.getAddPrintersActivityName();
277            if (!TextUtils.isEmpty(addPrinterClassName)) {
278                extras.putString(EXTRA_ADD_PRINTERS_TITLE,
279                        getString(R.string.print_menu_item_add_printers));
280                extras.putString(EXTRA_ADD_PRINTERS_COMPONENT_NAME,
281                        new ComponentName(installedService.serviceInfo.packageName,
282                                addPrinterClassName).flattenToString());
283            }
284
285            extras.putString(EXTRA_SERVICE_COMPONENT_NAME, componentName.flattenToString());
286
287            mPrintServicesCategory.addPreference(preference);
288        }
289
290        if (mPrintServicesCategory.getPreferenceCount() == 0) {
291            getPreferenceScreen().removePreference(mPrintServicesCategory);
292        } else {
293            final Preference addNewServicePreference = newAddServicePreferenceOrNull();
294            if (addNewServicePreference != null) {
295                mPrintServicesCategory.addPreference(addNewServicePreference);
296            }
297        }
298    }
299
300    private Preference newAddServicePreferenceOrNull() {
301        final Intent addNewServiceIntent = createAddNewServiceIntentOrNull();
302        if (addNewServiceIntent == null) {
303            return null;
304        }
305        Preference preference = new Preference(getContext());
306        preference.setTitle(R.string.print_menu_item_add_service);
307        preference.setIcon(R.drawable.ic_menu_add);
308        preference.setOrder(ORDER_LAST);
309        preference.setIntent(addNewServiceIntent);
310        preference.setPersistent(false);
311        return preference;
312    }
313
314    private Intent createAddNewServiceIntentOrNull() {
315        final String searchUri = Settings.Secure.getString(getContentResolver(),
316                Settings.Secure.PRINT_SERVICE_SEARCH_URI);
317        if (TextUtils.isEmpty(searchUri)) {
318            return null;
319        }
320        return new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri));
321    }
322
323    private void startSubSettingsIfNeeded() {
324        if (getArguments() == null) {
325            return;
326        }
327        String componentName = getArguments().getString(EXTRA_PRINT_SERVICE_COMPONENT_NAME);
328        if (componentName != null) {
329            getArguments().remove(EXTRA_PRINT_SERVICE_COMPONENT_NAME);
330            Preference prereference = findPreference(componentName);
331            if (prereference != null) {
332                prereference.performClick(getPreferenceScreen());
333            }
334        }
335    }
336
337    @Override
338    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
339        UserHandle selectedUser = mProfileSpinnerAdapter.getUserHandle(position);
340        if (selectedUser.getIdentifier() != UserHandle.myUserId()) {
341            Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);
342            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
343            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
344            getActivity().startActivityAsUser(intent, selectedUser);
345            // Go back to default selection, which is the first one
346            mSpinner.setSelection(0);
347        }
348    }
349
350    @Override
351    public void onNothingSelected(AdapterView<?> parent) {
352        // Nothing to do
353    }
354
355    @Override
356    public void onClick(View v) {
357        if (mAddNewServiceButton == v) {
358            final Intent addNewServiceIntent = createAddNewServiceIntentOrNull();
359            if (addNewServiceIntent != null) { // check again just in case.
360                try {
361                    startActivity(addNewServiceIntent);
362                } catch (ActivityNotFoundException e) {
363                    Log.w(TAG, "Unable to start activity", e);
364                }
365            }
366        }
367    }
368
369    private class SettingsPackageMonitor extends PackageMonitor {
370        @Override
371        public void onPackageAdded(String packageName, int uid) {
372            mHandler.obtainMessage().sendToTarget();
373        }
374
375        @Override
376        public void onPackageAppeared(String packageName, int reason) {
377            mHandler.obtainMessage().sendToTarget();
378        }
379
380        @Override
381        public void onPackageDisappeared(String packageName, int reason) {
382            mHandler.obtainMessage().sendToTarget();
383        }
384
385        @Override
386        public void onPackageRemoved(String packageName, int uid) {
387            mHandler.obtainMessage().sendToTarget();
388        }
389    }
390
391    private static abstract class SettingsContentObserver extends ContentObserver {
392
393        public SettingsContentObserver(Handler handler) {
394            super(handler);
395        }
396
397        public void register(ContentResolver contentResolver) {
398            contentResolver.registerContentObserver(Settings.Secure.getUriFor(
399                    Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
400        }
401
402        public void unregister(ContentResolver contentResolver) {
403            contentResolver.unregisterContentObserver(this);
404        }
405
406        @Override
407        public abstract void onChange(boolean selfChange, Uri uri);
408    }
409
410    private final class PrintJobsController implements LoaderCallbacks<List<PrintJobInfo>> {
411
412        @Override
413        public Loader<List<PrintJobInfo>> onCreateLoader(int id, Bundle args) {
414            if (id == LOADER_ID_PRINT_JOBS_LOADER) {
415                return new PrintJobsLoader(getActivity());
416            }
417            return null;
418        }
419
420        @Override
421        public void onLoadFinished(Loader<List<PrintJobInfo>> loader,
422                List<PrintJobInfo> printJobs) {
423            if (printJobs == null || printJobs.isEmpty()) {
424                getPreferenceScreen().removePreference(mActivePrintJobsCategory);
425            } else {
426                if (getPreferenceScreen().findPreference(PRINT_JOBS_CATEGORY) == null) {
427                    getPreferenceScreen().addPreference(mActivePrintJobsCategory);
428                }
429
430                mActivePrintJobsCategory.removeAll();
431
432                final int printJobCount = printJobs.size();
433                for (int i = 0; i < printJobCount; i++) {
434                    PrintJobInfo printJob = printJobs.get(i);
435
436                    PreferenceScreen preference = getPreferenceManager()
437                            .createPreferenceScreen(getActivity());
438
439                    preference.setPersistent(false);
440                    preference.setFragment(PrintJobSettingsFragment.class.getName());
441                    preference.setKey(printJob.getId().flattenToString());
442
443                    switch (printJob.getState()) {
444                        case PrintJobInfo.STATE_QUEUED:
445                        case PrintJobInfo.STATE_STARTED: {
446                            if (!printJob.isCancelling()) {
447                                preference.setTitle(getString(
448                                        R.string.print_printing_state_title_template,
449                                        printJob.getLabel()));
450                            } else {
451                                preference.setTitle(getString(
452                                        R.string.print_cancelling_state_title_template,
453                                        printJob.getLabel()));
454                            }
455                        } break;
456
457                        case PrintJobInfo.STATE_FAILED: {
458                            preference.setTitle(getString(
459                                    R.string.print_failed_state_title_template,
460                                    printJob.getLabel()));
461                        } break;
462
463                        case PrintJobInfo.STATE_BLOCKED: {
464                            if (!printJob.isCancelling()) {
465                                preference.setTitle(getString(
466                                        R.string.print_blocked_state_title_template,
467                                        printJob.getLabel()));
468                            } else {
469                                preference.setTitle(getString(
470                                        R.string.print_cancelling_state_title_template,
471                                        printJob.getLabel()));
472                            }
473                        } break;
474                    }
475
476                    preference.setSummary(getString(R.string.print_job_summary,
477                            printJob.getPrinterName(), DateUtils.formatSameDayTime(
478                                    printJob.getCreationTime(), printJob.getCreationTime(),
479                                    DateFormat.SHORT, DateFormat.SHORT)));
480
481                    switch (printJob.getState()) {
482                        case PrintJobInfo.STATE_QUEUED:
483                        case PrintJobInfo.STATE_STARTED: {
484                            preference.setIcon(R.drawable.ic_print);
485                        } break;
486
487                        case PrintJobInfo.STATE_FAILED:
488                        case PrintJobInfo.STATE_BLOCKED: {
489                            preference.setIcon(R.drawable.ic_print_error);
490                        } break;
491                    }
492
493                    Bundle extras = preference.getExtras();
494                    extras.putString(EXTRA_PRINT_JOB_ID, printJob.getId().flattenToString());
495
496                    mActivePrintJobsCategory.addPreference(preference);
497                }
498            }
499        }
500
501        @Override
502        public void onLoaderReset(Loader<List<PrintJobInfo>> loader) {
503            getPreferenceScreen().removePreference(mActivePrintJobsCategory);
504        }
505    }
506
507    private static final class PrintJobsLoader extends AsyncTaskLoader<List<PrintJobInfo>> {
508
509        private static final String LOG_TAG = "PrintJobsLoader";
510
511        private static final boolean DEBUG = false;
512
513        private List<PrintJobInfo> mPrintJobs = new ArrayList<PrintJobInfo>();
514
515        private final PrintManager mPrintManager;
516
517        private PrintJobStateChangeListener mPrintJobStateChangeListener;
518
519        public PrintJobsLoader(Context context) {
520            super(context);
521            mPrintManager = ((PrintManager) context.getSystemService(
522                    Context.PRINT_SERVICE)).getGlobalPrintManagerForUser(
523                    context.getUserId());
524        }
525
526        @Override
527        public void deliverResult(List<PrintJobInfo> printJobs) {
528            if (isStarted()) {
529                super.deliverResult(printJobs);
530            }
531        }
532
533        @Override
534        protected void onStartLoading() {
535            if (DEBUG) {
536                Log.i(LOG_TAG, "onStartLoading()");
537            }
538            // If we already have a result, deliver it immediately.
539            if (!mPrintJobs.isEmpty()) {
540                deliverResult(new ArrayList<PrintJobInfo>(mPrintJobs));
541            }
542            // Start watching for changes.
543            if (mPrintJobStateChangeListener == null) {
544                mPrintJobStateChangeListener = new PrintJobStateChangeListener() {
545                    @Override
546                    public void onPrintJobStateChanged(PrintJobId printJobId) {
547                        onForceLoad();
548                    }
549                };
550                mPrintManager.addPrintJobStateChangeListener(
551                        mPrintJobStateChangeListener);
552            }
553            // If the data changed or we have no data - load it now.
554            if (mPrintJobs.isEmpty()) {
555                onForceLoad();
556            }
557        }
558
559        @Override
560        protected void onStopLoading() {
561            if (DEBUG) {
562                Log.i(LOG_TAG, "onStopLoading()");
563            }
564            // Cancel the load in progress if possible.
565            onCancelLoad();
566        }
567
568        @Override
569        protected void onReset() {
570            if (DEBUG) {
571                Log.i(LOG_TAG, "onReset()");
572            }
573            // Stop loading.
574            onStopLoading();
575            // Clear the cached result.
576            mPrintJobs.clear();
577            // Stop watching for changes.
578            if (mPrintJobStateChangeListener != null) {
579                mPrintManager.removePrintJobStateChangeListener(
580                        mPrintJobStateChangeListener);
581                mPrintJobStateChangeListener = null;
582            }
583        }
584
585        @Override
586        public List<PrintJobInfo> loadInBackground() {
587            List<PrintJobInfo> printJobInfos = null;
588            List<PrintJob> printJobs = mPrintManager.getPrintJobs();
589            final int printJobCount = printJobs.size();
590            for (int i = 0; i < printJobCount; i++) {
591                PrintJobInfo printJob = printJobs.get(i).getInfo();
592                if (shouldShowToUser(printJob)) {
593                    if (printJobInfos == null) {
594                        printJobInfos = new ArrayList<PrintJobInfo>();
595                    }
596                    printJobInfos.add(printJob);
597                }
598            }
599            return printJobInfos;
600        }
601
602        private static boolean shouldShowToUser(PrintJobInfo printJob) {
603            switch (printJob.getState()) {
604                case PrintJobInfo.STATE_QUEUED:
605                case PrintJobInfo.STATE_STARTED:
606                case PrintJobInfo.STATE_BLOCKED:
607                case PrintJobInfo.STATE_FAILED: {
608                    return true;
609                }
610            }
611            return false;
612        }
613    }
614
615    public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
616            new BaseSearchIndexProvider() {
617        @Override
618        public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
619            List<SearchIndexableRaw> indexables = new ArrayList<SearchIndexableRaw>();
620
621            PackageManager packageManager = context.getPackageManager();
622            PrintManager printManager = (PrintManager) context.getSystemService(
623                    Context.PRINT_SERVICE);
624
625            String screenTitle = context.getResources().getString(R.string.print_settings);
626            SearchIndexableRaw data = new SearchIndexableRaw(context);
627            data.title = screenTitle;
628            data.screenTitle = screenTitle;
629            indexables.add(data);
630
631            // Indexing all services, regardless if enabled.
632            List<PrintServiceInfo> services = printManager.getInstalledPrintServices();
633            final int serviceCount = services.size();
634            for (int i = 0; i < serviceCount; i++) {
635                PrintServiceInfo service = services.get(i);
636
637                ComponentName componentName = new ComponentName(
638                        service.getResolveInfo().serviceInfo.packageName,
639                        service.getResolveInfo().serviceInfo.name);
640
641                data = new SearchIndexableRaw(context);
642                data.key = componentName.flattenToString();
643                data.title = service.getResolveInfo().loadLabel(packageManager).toString();
644                data.summaryOn = context.getString(R.string.print_feature_state_on);
645                data.summaryOff = context.getString(R.string.print_feature_state_off);
646                data.screenTitle = screenTitle;
647                indexables.add(data);
648            }
649
650            return indexables;
651        }
652
653        @Override
654        public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
655                boolean enabled) {
656            List<SearchIndexableResource> indexables = new ArrayList<SearchIndexableResource>();
657            SearchIndexableResource indexable = new SearchIndexableResource(context);
658            indexable.xmlResId = R.xml.print_settings;
659            indexables.add(indexable);
660            return indexables;
661        }
662    };
663}
664