When the search view is attached and detached we announce that for accessibility. The trouble is that if the activity is being torn down we are trying to access resources from a fragment that is detached and the qcrash occurs. This change does not try to access resources if the activity is finishing and also we do not load resource strings if accessibility is not enabled. bug:11127814 Change-Id: If3e97b6e94687775386a43c8fa54fd45140306eb
802 lines
30 KiB
Java
802 lines
30 KiB
Java
/*
|
|
* Copyright (C) 2013 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.settings.print;
|
|
|
|
import android.app.ActionBar;
|
|
import android.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.app.Dialog;
|
|
import android.app.LoaderManager;
|
|
import android.content.ComponentName;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.Loader;
|
|
import android.content.pm.PackageInfo;
|
|
import android.content.pm.PackageManager.NameNotFoundException;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.database.ContentObserver;
|
|
import android.database.DataSetObserver;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.ColorDrawable;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.preference.PreferenceActivity;
|
|
import android.print.PrintManager;
|
|
import android.print.PrinterDiscoverySession;
|
|
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
|
|
import android.print.PrinterId;
|
|
import android.print.PrinterInfo;
|
|
import android.provider.Settings;
|
|
import android.text.TextUtils;
|
|
import android.util.Log;
|
|
import android.view.Gravity;
|
|
import android.view.Menu;
|
|
import android.view.MenuInflater;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.accessibility.AccessibilityManager;
|
|
import android.widget.BaseAdapter;
|
|
import android.widget.CompoundButton;
|
|
import android.widget.CompoundButton.OnCheckedChangeListener;
|
|
import android.widget.Filter;
|
|
import android.widget.Filterable;
|
|
import android.widget.ImageView;
|
|
import android.widget.ListView;
|
|
import android.widget.SearchView;
|
|
import android.widget.TextView;
|
|
|
|
import com.android.settings.R;
|
|
import com.android.settings.SettingsPreferenceFragment;
|
|
import com.android.settings.print.PrintSettingsFragment.ToggleSwitch;
|
|
import com.android.settings.print.PrintSettingsFragment.ToggleSwitch.OnBeforeCheckedChangeListener;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
/**
|
|
* Fragment with print service settings.
|
|
*/
|
|
public class PrintServiceSettingsFragment extends SettingsPreferenceFragment
|
|
implements DialogInterface.OnClickListener {
|
|
|
|
private static final int LOADER_ID_PRINTERS_LOADER = 1;
|
|
|
|
private static final int DIALOG_ID_ENABLE_WARNING = 1;
|
|
|
|
private final SettingsContentObserver mSettingsContentObserver =
|
|
new SettingsContentObserver(new Handler()) {
|
|
@Override
|
|
public void onChange(boolean selfChange, Uri uri) {
|
|
updateUiForServiceState();
|
|
}
|
|
};
|
|
|
|
private final DataSetObserver mDataObserver = new DataSetObserver() {
|
|
@Override
|
|
public void onChanged() {
|
|
invalidateOptionsMenuIfNeeded();
|
|
updateEmptyView();
|
|
}
|
|
|
|
@Override
|
|
public void onInvalidated() {
|
|
invalidateOptionsMenuIfNeeded();
|
|
}
|
|
|
|
private void invalidateOptionsMenuIfNeeded() {
|
|
final int unfilteredItemCount = mPrintersAdapter.getUnfilteredCount();
|
|
if ((mLastUnfilteredItemCount <= 0 && unfilteredItemCount > 0)
|
|
|| mLastUnfilteredItemCount > 0 && unfilteredItemCount <= 0) {
|
|
getActivity().invalidateOptionsMenu();
|
|
}
|
|
mLastUnfilteredItemCount = unfilteredItemCount;
|
|
}
|
|
};
|
|
|
|
private ToggleSwitch mToggleSwitch;
|
|
|
|
private String mPreferenceKey;
|
|
|
|
private CharSequence mSettingsTitle;
|
|
private Intent mSettingsIntent;
|
|
|
|
private CharSequence mAddPrintersTitle;
|
|
private Intent mAddPrintersIntent;
|
|
|
|
private CharSequence mEnableWarningTitle;
|
|
private CharSequence mEnableWarningMessage;
|
|
|
|
private ComponentName mComponentName;
|
|
|
|
private PrintersAdapter mPrintersAdapter;
|
|
|
|
private int mLastUnfilteredItemCount;
|
|
|
|
private boolean mServiceEnabled;
|
|
|
|
private AnnounceFilterResult mAnnounceFilterResult;
|
|
|
|
@Override
|
|
public void onResume() {
|
|
super.onResume();
|
|
mSettingsContentObserver.register(getContentResolver());
|
|
updateEmptyView();
|
|
updateUiForServiceState();
|
|
}
|
|
|
|
@Override
|
|
public void onPause() {
|
|
mSettingsContentObserver.unregister(getContentResolver());
|
|
if (mAnnounceFilterResult != null) {
|
|
mAnnounceFilterResult.remove();
|
|
}
|
|
super.onPause();
|
|
}
|
|
|
|
@Override
|
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
|
super.onViewCreated(view, savedInstanceState);
|
|
initComponents();
|
|
updateUiForArguments();
|
|
}
|
|
|
|
@Override
|
|
public void onDestroyView() {
|
|
getActivity().getActionBar().setCustomView(null);
|
|
mToggleSwitch.setOnBeforeCheckedChangeListener(null);
|
|
super.onDestroyView();
|
|
}
|
|
|
|
private void onPreferenceToggled(String preferenceKey, boolean enabled) {
|
|
ComponentName service = ComponentName.unflattenFromString(preferenceKey);
|
|
List<ComponentName> services = SettingsUtils.readEnabledPrintServices(getActivity());
|
|
if (enabled) {
|
|
services.add(service);
|
|
} else {
|
|
services.remove(service);
|
|
}
|
|
SettingsUtils.writeEnabledPrintServices(getActivity(), services);
|
|
}
|
|
|
|
@Override
|
|
public Dialog onCreateDialog(int dialogId) {
|
|
CharSequence title = null;
|
|
CharSequence message = null;
|
|
switch (dialogId) {
|
|
case DIALOG_ID_ENABLE_WARNING:
|
|
title = mEnableWarningTitle;
|
|
message = mEnableWarningMessage;
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException();
|
|
}
|
|
return new AlertDialog.Builder(getActivity())
|
|
.setTitle(title)
|
|
.setIconAttribute(android.R.attr.alertDialogIcon)
|
|
.setMessage(message)
|
|
.setCancelable(true)
|
|
.setPositiveButton(android.R.string.ok, this)
|
|
.setNegativeButton(android.R.string.cancel, this)
|
|
.create();
|
|
}
|
|
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
final boolean checked;
|
|
switch (which) {
|
|
case DialogInterface.BUTTON_POSITIVE:
|
|
checked = true;
|
|
mToggleSwitch.setCheckedInternal(checked);
|
|
getArguments().putBoolean(PrintSettingsFragment.EXTRA_CHECKED, checked);
|
|
onPreferenceToggled(mPreferenceKey, checked);
|
|
break;
|
|
case DialogInterface.BUTTON_NEGATIVE:
|
|
checked = false;
|
|
mToggleSwitch.setCheckedInternal(checked);
|
|
getArguments().putBoolean(PrintSettingsFragment.EXTRA_CHECKED, checked);
|
|
onPreferenceToggled(mPreferenceKey, checked);
|
|
break;
|
|
default:
|
|
throw new IllegalArgumentException();
|
|
}
|
|
}
|
|
|
|
private void updateEmptyView() {
|
|
ListView listView = getListView();
|
|
ViewGroup contentRoot = (ViewGroup) listView.getParent();
|
|
View emptyView = listView.getEmptyView();
|
|
if (!mToggleSwitch.isChecked()) {
|
|
if (emptyView != null && emptyView.getId() != R.id.empty_print_state) {
|
|
contentRoot.removeView(emptyView);
|
|
emptyView = null;
|
|
}
|
|
if (emptyView == null) {
|
|
emptyView = getActivity().getLayoutInflater().inflate(
|
|
R.layout.empty_print_state, contentRoot, false);
|
|
emptyView.setContentDescription(getString(R.string.print_service_disabled));
|
|
TextView textView = (TextView) emptyView.findViewById(R.id.message);
|
|
textView.setText(R.string.print_service_disabled);
|
|
contentRoot.addView(emptyView);
|
|
listView.setEmptyView(emptyView);
|
|
}
|
|
} else if (mPrintersAdapter.getUnfilteredCount() <= 0) {
|
|
if (emptyView != null
|
|
&& emptyView.getId() != R.id.empty_printers_list_service_enabled) {
|
|
contentRoot.removeView(emptyView);
|
|
emptyView = null;
|
|
}
|
|
if (emptyView == null) {
|
|
emptyView = getActivity().getLayoutInflater().inflate(
|
|
R.layout.empty_printers_list_service_enabled, contentRoot, false);
|
|
contentRoot.addView(emptyView);
|
|
listView.setEmptyView(emptyView);
|
|
}
|
|
} else if (mPrintersAdapter.getCount() <= 0) {
|
|
if (emptyView != null && emptyView.getId() != R.id.empty_print_state) {
|
|
contentRoot.removeView(emptyView);
|
|
emptyView = null;
|
|
}
|
|
if (emptyView == null) {
|
|
emptyView = getActivity().getLayoutInflater().inflate(
|
|
R.layout.empty_print_state, contentRoot, false);
|
|
emptyView.setContentDescription(getString(R.string.print_no_printers_found));
|
|
TextView textView = (TextView) emptyView.findViewById(R.id.message);
|
|
textView.setText(R.string.print_no_printers_found);
|
|
contentRoot.addView(emptyView);
|
|
listView.setEmptyView(emptyView);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void updateUiForServiceState() {
|
|
List<ComponentName> services = SettingsUtils.readEnabledPrintServices(getActivity());
|
|
mServiceEnabled = services.contains(mComponentName);
|
|
if (mServiceEnabled) {
|
|
mToggleSwitch.setCheckedInternal(true);
|
|
mPrintersAdapter.enable();
|
|
} else {
|
|
mToggleSwitch.setCheckedInternal(false);
|
|
mPrintersAdapter.disable();
|
|
}
|
|
getActivity().invalidateOptionsMenu();
|
|
}
|
|
|
|
private void initComponents() {
|
|
mPrintersAdapter = new PrintersAdapter();
|
|
mPrintersAdapter.registerDataSetObserver(mDataObserver);
|
|
|
|
mToggleSwitch = createAndAddActionBarToggleSwitch(getActivity());
|
|
mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() {
|
|
@Override
|
|
public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) {
|
|
if (checked) {
|
|
if (!TextUtils.isEmpty(mEnableWarningMessage)) {
|
|
toggleSwitch.setCheckedInternal(false);
|
|
getArguments().putBoolean(PrintSettingsFragment.EXTRA_CHECKED, false);
|
|
showDialog(DIALOG_ID_ENABLE_WARNING);
|
|
return true;
|
|
}
|
|
onPreferenceToggled(mPreferenceKey, true);
|
|
} else {
|
|
onPreferenceToggled(mPreferenceKey, false);
|
|
}
|
|
return false;
|
|
}
|
|
});
|
|
mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
|
@Override
|
|
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
|
updateEmptyView();
|
|
}
|
|
});
|
|
|
|
getListView().setSelector(new ColorDrawable(Color.TRANSPARENT));
|
|
getListView().setAdapter(mPrintersAdapter);
|
|
}
|
|
|
|
private void updateUiForArguments() {
|
|
Bundle arguments = getArguments();
|
|
|
|
// Key.
|
|
mPreferenceKey = arguments.getString(PrintSettingsFragment.EXTRA_PREFERENCE_KEY);
|
|
|
|
// Enabled.
|
|
final boolean enabled = arguments.getBoolean(PrintSettingsFragment.EXTRA_CHECKED);
|
|
mToggleSwitch.setCheckedInternal(enabled);
|
|
|
|
// Title.
|
|
PreferenceActivity activity = (PreferenceActivity) getActivity();
|
|
if (!activity.onIsMultiPane() || activity.onIsHidingHeaders()) {
|
|
// PreferenceActivity allows passing as an extra only title by its
|
|
// resource id but we do not have the resource id for the print
|
|
// service label. Therefore, we do it ourselves.
|
|
String title = arguments.getString(PrintSettingsFragment.EXTRA_TITLE);
|
|
getActivity().setTitle(title);
|
|
}
|
|
|
|
// Settings title and intent.
|
|
String settingsTitle = arguments.getString(PrintSettingsFragment.EXTRA_SETTINGS_TITLE);
|
|
String settingsComponentName = arguments.getString(
|
|
PrintSettingsFragment.EXTRA_SETTINGS_COMPONENT_NAME);
|
|
if (!TextUtils.isEmpty(settingsTitle) && !TextUtils.isEmpty(settingsComponentName)) {
|
|
Intent settingsIntent = new Intent(Intent.ACTION_MAIN).setComponent(
|
|
ComponentName.unflattenFromString(settingsComponentName.toString()));
|
|
List<ResolveInfo> resolvedActivities = getPackageManager().queryIntentActivities(
|
|
settingsIntent, 0);
|
|
if (!resolvedActivities.isEmpty()) {
|
|
// The activity is a component name, therefore it is one or none.
|
|
if (resolvedActivities.get(0).activityInfo.exported) {
|
|
mSettingsTitle = settingsTitle;
|
|
mSettingsIntent = settingsIntent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add printers title and intent.
|
|
String addPrintersTitle = arguments.getString(
|
|
PrintSettingsFragment.EXTRA_ADD_PRINTERS_TITLE);
|
|
String addPrintersComponentName =
|
|
arguments.getString(PrintSettingsFragment.EXTRA_ADD_PRINTERS_COMPONENT_NAME);
|
|
if (!TextUtils.isEmpty(addPrintersTitle)
|
|
&& !TextUtils.isEmpty(addPrintersComponentName)) {
|
|
Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN).setComponent(
|
|
ComponentName.unflattenFromString(addPrintersComponentName.toString()));
|
|
List<ResolveInfo> resolvedActivities = getPackageManager().queryIntentActivities(
|
|
addPritnersIntent, 0);
|
|
if (!resolvedActivities.isEmpty()) {
|
|
// The activity is a component name, therefore it is one or none.
|
|
if (resolvedActivities.get(0).activityInfo.exported) {
|
|
mAddPrintersTitle = addPrintersTitle;
|
|
mAddPrintersIntent = addPritnersIntent;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Enable warning title.
|
|
mEnableWarningTitle = arguments.getCharSequence(
|
|
PrintSettingsFragment.EXTRA_ENABLE_WARNING_TITLE);
|
|
|
|
// Enable warning message.
|
|
mEnableWarningMessage = arguments.getCharSequence(
|
|
PrintSettingsFragment.EXTRA_ENABLE_WARNING_MESSAGE);
|
|
|
|
// Component name.
|
|
mComponentName = ComponentName.unflattenFromString(arguments
|
|
.getString(PrintSettingsFragment.EXTRA_SERVICE_COMPONENT_NAME));
|
|
|
|
setHasOptionsMenu(true);
|
|
}
|
|
|
|
@Override
|
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
|
super.onCreateOptionsMenu(menu, inflater);
|
|
inflater.inflate(R.menu.print_service_settings, menu);
|
|
|
|
MenuItem addPrinters = menu.findItem(R.id.print_menu_item_add_printer);
|
|
if (mServiceEnabled && !TextUtils.isEmpty(mAddPrintersTitle)
|
|
&& mAddPrintersIntent != null) {
|
|
addPrinters.setIntent(mAddPrintersIntent);
|
|
} else {
|
|
menu.removeItem(R.id.print_menu_item_add_printer);
|
|
}
|
|
|
|
MenuItem settings = menu.findItem(R.id.print_menu_item_settings);
|
|
if (mServiceEnabled && !TextUtils.isEmpty(mSettingsTitle)
|
|
&& mSettingsIntent != null) {
|
|
settings.setIntent(mSettingsIntent);
|
|
} else {
|
|
menu.removeItem(R.id.print_menu_item_settings);
|
|
}
|
|
|
|
MenuItem searchItem = menu.findItem(R.id.print_menu_item_search);
|
|
if (mServiceEnabled && mPrintersAdapter.getUnfilteredCount() > 0) {
|
|
SearchView searchView = (SearchView) searchItem.getActionView();
|
|
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
|
|
@Override
|
|
public boolean onQueryTextSubmit(String query) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onQueryTextChange(String searchString) {
|
|
((Filterable) getListView().getAdapter()).getFilter().filter(searchString);
|
|
return true;
|
|
}
|
|
});
|
|
searchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
|
@Override
|
|
public void onViewAttachedToWindow(View view) {
|
|
if (AccessibilityManager.getInstance(getActivity()).isEnabled()) {
|
|
view.announceForAccessibility(getString(
|
|
R.string.print_search_box_shown_utterance));
|
|
}
|
|
}
|
|
@Override
|
|
public void onViewDetachedFromWindow(View view) {
|
|
Activity activity = getActivity();
|
|
if (activity != null && !activity.isFinishing()
|
|
&& AccessibilityManager.getInstance(activity).isEnabled()) {
|
|
view.announceForAccessibility(getString(
|
|
R.string.print_search_box_hidden_utterance));
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
menu.removeItem(R.id.print_menu_item_search);
|
|
}
|
|
}
|
|
|
|
private ToggleSwitch createAndAddActionBarToggleSwitch(Activity activity) {
|
|
ToggleSwitch toggleSwitch = new ToggleSwitch(activity);
|
|
final int padding = activity.getResources().getDimensionPixelSize(
|
|
R.dimen.action_bar_switch_padding);
|
|
toggleSwitch.setPaddingRelative(0, 0, padding, 0);
|
|
activity.getActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
|
|
ActionBar.DISPLAY_SHOW_CUSTOM);
|
|
activity.getActionBar().setCustomView(toggleSwitch,
|
|
new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
|
|
ActionBar.LayoutParams.WRAP_CONTENT,
|
|
Gravity.CENTER_VERTICAL | Gravity.END));
|
|
return toggleSwitch;
|
|
}
|
|
|
|
private static abstract class SettingsContentObserver extends ContentObserver {
|
|
|
|
public SettingsContentObserver(Handler handler) {
|
|
super(handler);
|
|
}
|
|
|
|
public void register(ContentResolver contentResolver) {
|
|
contentResolver.registerContentObserver(Settings.Secure.getUriFor(
|
|
Settings.Secure.ENABLED_PRINT_SERVICES), false, this);
|
|
}
|
|
|
|
public void unregister(ContentResolver contentResolver) {
|
|
contentResolver.unregisterContentObserver(this);
|
|
}
|
|
|
|
@Override
|
|
public abstract void onChange(boolean selfChange, Uri uri);
|
|
}
|
|
|
|
private final class AnnounceFilterResult implements Runnable {
|
|
private static final int SEARCH_RESULT_ANNOUNCEMENT_DELAY = 1000; // 1 sec
|
|
|
|
public void post() {
|
|
remove();
|
|
getListView().postDelayed(this, SEARCH_RESULT_ANNOUNCEMENT_DELAY);
|
|
}
|
|
|
|
public void remove() {
|
|
getListView().removeCallbacks(this);
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
final int count = getListView().getAdapter().getCount();
|
|
final String text;
|
|
if (count <= 0) {
|
|
text = getString(R.string.print_no_printers_found);
|
|
} else {
|
|
text = getActivity().getResources().getQuantityString(
|
|
R.plurals.print_search_result_count_utterance, count, count);
|
|
}
|
|
getListView().announceForAccessibility(text);
|
|
}
|
|
}
|
|
|
|
private void announceSearchResult() {
|
|
if (mAnnounceFilterResult == null) {
|
|
mAnnounceFilterResult = new AnnounceFilterResult();
|
|
}
|
|
mAnnounceFilterResult.post();
|
|
}
|
|
|
|
private final class PrintersAdapter extends BaseAdapter
|
|
implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>, Filterable {
|
|
private final Object mLock = new Object();
|
|
|
|
private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
|
|
|
|
private final List<PrinterInfo> mFilteredPrinters = new ArrayList<PrinterInfo>();
|
|
|
|
private CharSequence mLastSearchString;
|
|
|
|
public void enable() {
|
|
getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
|
|
}
|
|
|
|
public void disable() {
|
|
getLoaderManager().destroyLoader(LOADER_ID_PRINTERS_LOADER);
|
|
mPrinters.clear();
|
|
}
|
|
|
|
public int getUnfilteredCount() {
|
|
return mPrinters.size();
|
|
}
|
|
|
|
@Override
|
|
public Filter getFilter() {
|
|
return new Filter() {
|
|
@Override
|
|
protected FilterResults performFiltering(CharSequence constraint) {
|
|
synchronized (mLock) {
|
|
if (TextUtils.isEmpty(constraint)) {
|
|
return null;
|
|
}
|
|
FilterResults results = new FilterResults();
|
|
List<PrinterInfo> filteredPrinters = new ArrayList<PrinterInfo>();
|
|
String constraintLowerCase = constraint.toString().toLowerCase();
|
|
final int printerCount = mPrinters.size();
|
|
for (int i = 0; i < printerCount; i++) {
|
|
PrinterInfo printer = mPrinters.get(i);
|
|
if (printer.getName().toLowerCase().contains(constraintLowerCase)) {
|
|
filteredPrinters.add(printer);
|
|
}
|
|
}
|
|
results.values = filteredPrinters;
|
|
results.count = filteredPrinters.size();
|
|
return results;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
protected void publishResults(CharSequence constraint, FilterResults results) {
|
|
final boolean resultCountChanged;
|
|
synchronized (mLock) {
|
|
final int oldPrinterCount = mFilteredPrinters.size();
|
|
mLastSearchString = constraint;
|
|
mFilteredPrinters.clear();
|
|
if (results == null) {
|
|
mFilteredPrinters.addAll(mPrinters);
|
|
} else {
|
|
List<PrinterInfo> printers = (List<PrinterInfo>) results.values;
|
|
mFilteredPrinters.addAll(printers);
|
|
}
|
|
resultCountChanged = (oldPrinterCount != mFilteredPrinters.size());
|
|
}
|
|
if (resultCountChanged) {
|
|
announceSearchResult();
|
|
}
|
|
notifyDataSetChanged();
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public int getCount() {
|
|
synchronized (mLock) {
|
|
return mFilteredPrinters.size();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Object getItem(int position) {
|
|
synchronized (mLock) {
|
|
return mFilteredPrinters.get(position);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public long getItemId(int position) {
|
|
return position;
|
|
}
|
|
|
|
@Override
|
|
public View getView(int position, View convertView, ViewGroup parent) {
|
|
if (convertView == null) {
|
|
convertView = getActivity().getLayoutInflater().inflate(
|
|
R.layout.printer_dropdown_item, parent, false);
|
|
}
|
|
|
|
PrinterInfo printer = (PrinterInfo) getItem(position);
|
|
CharSequence title = printer.getName();
|
|
CharSequence subtitle = null;
|
|
Drawable icon = null;
|
|
try {
|
|
PackageInfo packageInfo = getPackageManager().getPackageInfo(
|
|
printer.getId().getServiceName().getPackageName(), 0);
|
|
subtitle = packageInfo.applicationInfo.loadLabel(getPackageManager());
|
|
icon = packageInfo.applicationInfo.loadIcon(getPackageManager());
|
|
} catch (NameNotFoundException nnfe) {
|
|
/* ignore */
|
|
}
|
|
|
|
TextView titleView = (TextView) convertView.findViewById(R.id.title);
|
|
titleView.setText(title);
|
|
|
|
TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
|
|
if (!TextUtils.isEmpty(subtitle)) {
|
|
subtitleView.setText(subtitle);
|
|
subtitleView.setVisibility(View.VISIBLE);
|
|
} else {
|
|
subtitleView.setText(null);
|
|
subtitleView.setVisibility(View.GONE);
|
|
}
|
|
|
|
ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
|
|
if (icon != null) {
|
|
iconView.setImageDrawable(icon);
|
|
iconView.setVisibility(View.VISIBLE);
|
|
} else {
|
|
iconView.setVisibility(View.GONE);
|
|
}
|
|
|
|
return convertView;
|
|
}
|
|
|
|
@Override
|
|
public boolean isEnabled(int position) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public Loader<List<PrinterInfo>> onCreateLoader(int id, Bundle args) {
|
|
if (id == LOADER_ID_PRINTERS_LOADER) {
|
|
return new PrintersLoader(getActivity());
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void onLoadFinished(Loader<List<PrinterInfo>> loader,
|
|
List<PrinterInfo> printers) {
|
|
synchronized (mLock) {
|
|
mPrinters.clear();
|
|
final int printerCount = printers.size();
|
|
for (int i = 0; i < printerCount; i++) {
|
|
PrinterInfo printer = printers.get(i);
|
|
if (printer.getId().getServiceName().equals(mComponentName)) {
|
|
mPrinters.add(printer);
|
|
}
|
|
}
|
|
mFilteredPrinters.clear();
|
|
mFilteredPrinters.addAll(mPrinters);
|
|
if (!TextUtils.isEmpty(mLastSearchString)) {
|
|
getFilter().filter(mLastSearchString);
|
|
}
|
|
}
|
|
notifyDataSetChanged();
|
|
}
|
|
|
|
@Override
|
|
public void onLoaderReset(Loader<List<PrinterInfo>> loader) {
|
|
synchronized (mLock) {
|
|
mPrinters.clear();
|
|
mFilteredPrinters.clear();
|
|
mLastSearchString = null;
|
|
}
|
|
notifyDataSetInvalidated();
|
|
}
|
|
}
|
|
|
|
private static class PrintersLoader extends Loader<List<PrinterInfo>> {
|
|
|
|
private static final String LOG_TAG = "PrintersLoader";
|
|
|
|
private static final boolean DEBUG = false;
|
|
|
|
private final Map<PrinterId, PrinterInfo> mPrinters =
|
|
new LinkedHashMap<PrinterId, PrinterInfo>();
|
|
|
|
private PrinterDiscoverySession mDiscoverySession;
|
|
|
|
public PrintersLoader(Context context) {
|
|
super(context);
|
|
}
|
|
|
|
@Override
|
|
public void deliverResult(List<PrinterInfo> printers) {
|
|
if (isStarted()) {
|
|
super.deliverResult(printers);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onStartLoading() {
|
|
if (DEBUG) {
|
|
Log.i(LOG_TAG, "onStartLoading()");
|
|
}
|
|
// The contract is that if we already have a valid,
|
|
// result the we have to deliver it immediately.
|
|
if (!mPrinters.isEmpty()) {
|
|
deliverResult(new ArrayList<PrinterInfo>(mPrinters.values()));
|
|
}
|
|
// We want to start discovery at this point.
|
|
onForceLoad();
|
|
}
|
|
|
|
@Override
|
|
protected void onStopLoading() {
|
|
if (DEBUG) {
|
|
Log.i(LOG_TAG, "onStopLoading()");
|
|
}
|
|
onCancelLoad();
|
|
}
|
|
|
|
@Override
|
|
protected void onForceLoad() {
|
|
if (DEBUG) {
|
|
Log.i(LOG_TAG, "onForceLoad()");
|
|
}
|
|
loadInternal();
|
|
}
|
|
|
|
@Override
|
|
protected boolean onCancelLoad() {
|
|
if (DEBUG) {
|
|
Log.i(LOG_TAG, "onCancelLoad()");
|
|
}
|
|
return cancelInternal();
|
|
}
|
|
|
|
@Override
|
|
protected void onReset() {
|
|
if (DEBUG) {
|
|
Log.i(LOG_TAG, "onReset()");
|
|
}
|
|
onStopLoading();
|
|
mPrinters.clear();
|
|
if (mDiscoverySession != null) {
|
|
mDiscoverySession.destroy();
|
|
mDiscoverySession = null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onAbandon() {
|
|
if (DEBUG) {
|
|
Log.i(LOG_TAG, "onAbandon()");
|
|
}
|
|
onStopLoading();
|
|
}
|
|
|
|
private boolean cancelInternal() {
|
|
if (mDiscoverySession != null
|
|
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
|
|
mDiscoverySession.stopPrinterDiscovery();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private void loadInternal() {
|
|
if (mDiscoverySession == null) {
|
|
PrintManager printManager = (PrintManager) getContext()
|
|
.getSystemService(Context.PRINT_SERVICE);
|
|
mDiscoverySession = printManager.createPrinterDiscoverySession();
|
|
mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
|
|
@Override
|
|
public void onPrintersChanged() {
|
|
deliverResult(new ArrayList<PrinterInfo>(
|
|
mDiscoverySession.getPrinters()));
|
|
}
|
|
});
|
|
}
|
|
mDiscoverySession.startPrinterDisovery(null);
|
|
}
|
|
}
|
|
}
|
|
|