blob: cee16c8b29e9001277be046bd6c3668a8b7af577 [file] [log] [blame]
Svetoslav269403b2013-08-14 17:31:04 -07001/*
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
Svetoslava798c0a2014-05-15 10:47:19 -070017package com.android.printspooler.ui;
Svetoslav269403b2013-08-14 17:31:04 -070018
19import android.app.Activity;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080020import android.app.LoaderManager;
Svetoslav Ganov860f8a62013-09-14 00:59:03 -070021import android.content.Context;
Svetoslav269403b2013-08-14 17:31:04 -070022import android.content.Intent;
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -080023import android.content.IntentSender.SendIntentException;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080024import android.content.Loader;
Svetoslav269403b2013-08-14 17:31:04 -070025import android.content.pm.PackageInfo;
Svetoslav269403b2013-08-14 17:31:04 -070026import android.content.pm.PackageManager.NameNotFoundException;
Svetoslav Ganov264c5662013-10-05 12:58:17 -070027import android.database.DataSetObserver;
Svetoslav39e71de2013-10-02 19:30:32 -070028import android.graphics.drawable.Drawable;
Svetoslav269403b2013-08-14 17:31:04 -070029import android.os.Bundle;
Svetoslav Ganov860f8a62013-09-14 00:59:03 -070030import android.print.PrintManager;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080031import android.print.PrintServicesLoader;
Svetoslav269403b2013-08-14 17:31:04 -070032import android.print.PrinterId;
33import android.print.PrinterInfo;
34import android.printservice.PrintServiceInfo;
Svetoslav Ganov0ea7d1e2013-10-05 11:46:48 -070035import android.provider.Settings;
Svetoslav269403b2013-08-14 17:31:04 -070036import android.text.TextUtils;
Svetoslav Ganov860f8a62013-09-14 00:59:03 -070037import android.util.Log;
Philip P. Moltmann443075a2016-01-26 13:04:21 -080038import android.util.TypedValue;
Svetoslav1c664b62013-11-04 12:30:08 -080039import android.view.ContextMenu;
40import android.view.ContextMenu.ContextMenuInfo;
Svetoslav269403b2013-08-14 17:31:04 -070041import android.view.Menu;
Svetoslav269403b2013-08-14 17:31:04 -070042import android.view.MenuItem;
43import android.view.View;
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -080044import android.view.View.OnClickListener;
Svetoslav269403b2013-08-14 17:31:04 -070045import android.view.ViewGroup;
Svetoslav53e8a262013-10-08 11:25:32 -070046import android.view.accessibility.AccessibilityManager;
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -070047import android.widget.AdapterView;
Svetoslav1c664b62013-11-04 12:30:08 -080048import android.widget.AdapterView.AdapterContextMenuInfo;
Svetoslav269403b2013-08-14 17:31:04 -070049import android.widget.BaseAdapter;
50import android.widget.Filter;
51import android.widget.Filterable;
Svetoslav39e71de2013-10-02 19:30:32 -070052import android.widget.ImageView;
Philip P. Moltmann66c96592016-02-24 11:32:43 -080053import android.widget.LinearLayout;
Svetoslav269403b2013-08-14 17:31:04 -070054import android.widget.ListView;
55import android.widget.SearchView;
56import android.widget.TextView;
Philip P. Moltmann1f467792016-01-08 14:02:57 -080057import android.widget.Toast;
Svetoslav269403b2013-08-14 17:31:04 -070058
Svetoslava798c0a2014-05-15 10:47:19 -070059import com.android.printspooler.R;
60
Svetoslav269403b2013-08-14 17:31:04 -070061import java.util.ArrayList;
62import java.util.List;
63
64/**
Svetoslava798c0a2014-05-15 10:47:19 -070065 * This is an activity for selecting a printer.
Svetoslav269403b2013-08-14 17:31:04 -070066 */
Philip P. Moltmann66c96592016-02-24 11:32:43 -080067public final class SelectPrinterActivity extends Activity implements
68 LoaderManager.LoaderCallbacks<List<PrintServiceInfo>> {
Svetoslav269403b2013-08-14 17:31:04 -070069
Svetoslav Ganov860f8a62013-09-14 00:59:03 -070070 private static final String LOG_TAG = "SelectPrinterFragment";
71
Philip P. Moltmann66c96592016-02-24 11:32:43 -080072 private static final int LOADER_ID_PRINT_REGISTRY = 1;
73 private static final int LOADER_ID_PRINT_REGISTRY_INT = 2;
74 private static final int LOADER_ID_ENABLED_PRINT_SERVICES = 3;
75
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -080076 public static final String INTENT_EXTRA_PRINTER = "INTENT_EXTRA_PRINTER";
Svetoslav269403b2013-08-14 17:31:04 -070077
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -080078 private static final String EXTRA_PRINTER = "EXTRA_PRINTER";
Svetoslav1c664b62013-11-04 12:30:08 -080079 private static final String EXTRA_PRINTER_ID = "EXTRA_PRINTER_ID";
80
Philip P. Moltmann66c96592016-02-24 11:32:43 -080081 private static final String KEY_NOT_FIRST_CREATE = "KEY_NOT_FIRST_CREATE";
82
Philip P. Moltmann03755a12015-11-25 13:35:41 -080083 /** If there are any enabled print services */
Philip P. Moltmann953639c2015-11-11 15:30:16 -080084 private boolean mHasEnabledPrintServices;
85
Svetoslava798c0a2014-05-15 10:47:19 -070086 private PrinterRegistry mPrinterRegistry;
Svetoslav269403b2013-08-14 17:31:04 -070087
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -070088 private ListView mListView;
89
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -070090 private AnnounceFilterResult mAnnounceFilterResult;
91
Philip P. Moltmann66c96592016-02-24 11:32:43 -080092 private void startAddPrinterActivity() {
93 startActivity(new Intent(this, AddPrinterActivity.class));
94 }
Philip P. Moltmann03755a12015-11-25 13:35:41 -080095
Svetoslav269403b2013-08-14 17:31:04 -070096 @Override
97 public void onCreate(Bundle savedInstanceState) {
98 super.onCreate(savedInstanceState);
Svetoslav309f6a02014-08-18 16:10:59 -070099 getActionBar().setIcon(R.drawable.ic_print);
Svetoslav269403b2013-08-14 17:31:04 -0700100
Svetoslava798c0a2014-05-15 10:47:19 -0700101 setContentView(R.layout.select_printer_activity);
102
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800103 mPrinterRegistry = new PrinterRegistry(this, null, LOADER_ID_PRINT_REGISTRY,
104 LOADER_ID_PRINT_REGISTRY_INT);
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700105
106 // Hook up the list view.
Svetoslava798c0a2014-05-15 10:47:19 -0700107 mListView = (ListView) findViewById(android.R.id.list);
Svetoslav Ganov264c5662013-10-05 12:58:17 -0700108 final DestinationAdapter adapter = new DestinationAdapter();
109 adapter.registerDataSetObserver(new DataSetObserver() {
110 @Override
111 public void onChanged() {
Svetoslava798c0a2014-05-15 10:47:19 -0700112 if (!isFinishing() && adapter.getCount() <= 0) {
Svetoslav Ganov264c5662013-10-05 12:58:17 -0700113 updateEmptyView(adapter);
114 }
115 }
116
117 @Override
118 public void onInvalidated() {
Svetoslava798c0a2014-05-15 10:47:19 -0700119 if (!isFinishing()) {
Svetoslav Ganov24c686b2013-10-05 18:52:06 -0700120 updateEmptyView(adapter);
121 }
Svetoslav Ganov264c5662013-10-05 12:58:17 -0700122 }
123 });
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700124 mListView.setAdapter(adapter);
125
126 mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
127 @Override
128 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Svetoslav1c664b62013-11-04 12:30:08 -0800129 if (!((DestinationAdapter) mListView.getAdapter()).isActionable(position)) {
130 return;
131 }
Svetoslava798c0a2014-05-15 10:47:19 -0700132
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700133 PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800134
135 if (printer == null) {
136 startAddPrinterActivity();
137 } else {
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -0800138 onPrinterSelected(printer);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800139 }
140 }
141 });
142
143 findViewById(R.id.button).setOnClickListener(new OnClickListener() {
144 @Override public void onClick(View v) {
145 startAddPrinterActivity();
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700146 }
147 });
148
Svetoslav1c664b62013-11-04 12:30:08 -0800149 registerForContextMenu(mListView);
Philip P. Moltmann1f467792016-01-08 14:02:57 -0800150
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800151 getLoaderManager().initLoader(LOADER_ID_ENABLED_PRINT_SERVICES, null, this);
152
153 // On first creation:
154 //
155 // If no services are installed, instantly open add printer dialog.
156 // If some are disabled and some are enabled show a toast to notify the user
157 if (savedInstanceState == null || !savedInstanceState.getBoolean(KEY_NOT_FIRST_CREATE)) {
158 List<PrintServiceInfo> allServices =
159 ((PrintManager) getSystemService(Context.PRINT_SERVICE))
160 .getPrintServices(PrintManager.ALL_SERVICES);
161 boolean hasEnabledServices = false;
162 boolean hasDisabledServices = false;
163
164 if (allServices != null) {
165 final int numServices = allServices.size();
166 for (int i = 0; i < numServices; i++) {
167 if (allServices.get(i).isEnabled()) {
168 hasEnabledServices = true;
169 } else {
170 hasDisabledServices = true;
171 }
172 }
173 }
174
175 if (!hasEnabledServices) {
176 startAddPrinterActivity();
177 } else if (hasDisabledServices) {
178 String disabledServicesSetting = Settings.Secure.getString(getContentResolver(),
179 Settings.Secure.DISABLED_PRINT_SERVICES);
180 if (!TextUtils.isEmpty(disabledServicesSetting)) {
181 Toast.makeText(this, getString(R.string.print_services_disabled_toast),
182 Toast.LENGTH_LONG).show();
183 }
184 }
Philip P. Moltmann1f467792016-01-08 14:02:57 -0800185 }
Svetoslav269403b2013-08-14 17:31:04 -0700186 }
187
188 @Override
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800189 protected void onSaveInstanceState(Bundle outState) {
190 super.onSaveInstanceState(outState);
191 outState.putBoolean(KEY_NOT_FIRST_CREATE, true);
192 }
193
194 @Override
Svetoslava798c0a2014-05-15 10:47:19 -0700195 public boolean onCreateOptionsMenu(Menu menu) {
196 super.onCreateOptionsMenu(menu);
197
198 getMenuInflater().inflate(R.menu.select_printer_activity, menu);
Svetoslav269403b2013-08-14 17:31:04 -0700199
200 MenuItem searchItem = menu.findItem(R.id.action_search);
201 SearchView searchView = (SearchView) searchItem.getActionView();
202 searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
203 @Override
204 public boolean onQueryTextSubmit(String query) {
205 return true;
206 }
207
208 @Override
209 public boolean onQueryTextChange(String searchString) {
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700210 ((DestinationAdapter) mListView.getAdapter()).getFilter().filter(searchString);
Svetoslav269403b2013-08-14 17:31:04 -0700211 return true;
212 }
213 });
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700214 searchView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
215 @Override
216 public void onViewAttachedToWindow(View view) {
Svetoslava798c0a2014-05-15 10:47:19 -0700217 if (AccessibilityManager.getInstance(SelectPrinterActivity.this).isEnabled()) {
Svetoslav53e8a262013-10-08 11:25:32 -0700218 view.announceForAccessibility(getString(
219 R.string.print_search_box_shown_utterance));
220 }
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700221 }
222 @Override
223 public void onViewDetachedFromWindow(View view) {
Svetoslava798c0a2014-05-15 10:47:19 -0700224 if (!isFinishing() && AccessibilityManager.getInstance(
225 SelectPrinterActivity.this).isEnabled()) {
Svetoslav53e8a262013-10-08 11:25:32 -0700226 view.announceForAccessibility(getString(
227 R.string.print_search_box_hidden_utterance));
228 }
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700229 }
230 });
Svetoslav269403b2013-08-14 17:31:04 -0700231
Svetoslava798c0a2014-05-15 10:47:19 -0700232 return true;
Svetoslav269403b2013-08-14 17:31:04 -0700233 }
234
235 @Override
Svetoslav1c664b62013-11-04 12:30:08 -0800236 public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
237 if (view == mListView) {
238 final int position = ((AdapterContextMenuInfo) menuInfo).position;
239 PrinterInfo printer = (PrinterInfo) mListView.getAdapter().getItem(position);
240
241 menu.setHeaderTitle(printer.getName());
242
243 // Add the select menu item if applicable.
244 if (printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE) {
245 MenuItem selectItem = menu.add(Menu.NONE, R.string.print_select_printer,
246 Menu.NONE, R.string.print_select_printer);
247 Intent intent = new Intent();
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -0800248 intent.putExtra(EXTRA_PRINTER, printer);
Svetoslav1c664b62013-11-04 12:30:08 -0800249 selectItem.setIntent(intent);
250 }
251
252 // Add the forget menu item if applicable.
Svetoslava798c0a2014-05-15 10:47:19 -0700253 if (mPrinterRegistry.isFavoritePrinter(printer.getId())) {
Svetoslav1c664b62013-11-04 12:30:08 -0800254 MenuItem forgetItem = menu.add(Menu.NONE, R.string.print_forget_printer,
255 Menu.NONE, R.string.print_forget_printer);
256 Intent intent = new Intent();
257 intent.putExtra(EXTRA_PRINTER_ID, printer.getId());
258 forgetItem.setIntent(intent);
259 }
260 }
261 }
262
263 @Override
264 public boolean onContextItemSelected(MenuItem item) {
265 switch (item.getItemId()) {
266 case R.string.print_select_printer: {
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -0800267 PrinterInfo printer = item.getIntent().getParcelableExtra(EXTRA_PRINTER);
268 onPrinterSelected(printer);
Svetoslav1c664b62013-11-04 12:30:08 -0800269 } return true;
270
271 case R.string.print_forget_printer: {
Svetoslava798c0a2014-05-15 10:47:19 -0700272 PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
273 mPrinterRegistry.forgetFavoritePrinter(printerId);
Svetoslav1c664b62013-11-04 12:30:08 -0800274 } return true;
275 }
276 return false;
277 }
278
Philip P. Moltmann03755a12015-11-25 13:35:41 -0800279 /**
280 * Adjust the UI if the enabled print services changed.
281 */
282 private synchronized void onPrintServicesUpdate() {
Philip P. Moltmann953639c2015-11-11 15:30:16 -0800283 updateEmptyView((DestinationAdapter)mListView.getAdapter());
Svetoslava798c0a2014-05-15 10:47:19 -0700284 invalidateOptionsMenu();
Svetoslav269403b2013-08-14 17:31:04 -0700285 }
286
Philip P. Moltmann03755a12015-11-25 13:35:41 -0800287 @Override
288 public void onStart() {
289 super.onStart();
Philip P. Moltmann03755a12015-11-25 13:35:41 -0800290 onPrintServicesUpdate();
291 }
292
Svetoslav269403b2013-08-14 17:31:04 -0700293 @Override
Svetoslavebec4682013-10-08 17:17:08 -0700294 public void onPause() {
295 if (mAnnounceFilterResult != null) {
296 mAnnounceFilterResult.remove();
297 }
298 super.onPause();
299 }
300
301 @Override
Philip P. Moltmann03755a12015-11-25 13:35:41 -0800302 public void onStop() {
Philip P. Moltmann03755a12015-11-25 13:35:41 -0800303 super.onStop();
304 }
305
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -0800306 private void onPrinterSelected(PrinterInfo printer) {
Svetoslava798c0a2014-05-15 10:47:19 -0700307 Intent intent = new Intent();
Philip P. Moltmann63ce0b72016-03-08 11:16:56 -0800308 intent.putExtra(INTENT_EXTRA_PRINTER, printer);
Svetoslava798c0a2014-05-15 10:47:19 -0700309 setResult(RESULT_OK, intent);
310 finish();
311 }
312
Svetoslav Ganov264c5662013-10-05 12:58:17 -0700313 public void updateEmptyView(DestinationAdapter adapter) {
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700314 if (mListView.getEmptyView() == null) {
Svetoslava798c0a2014-05-15 10:47:19 -0700315 View emptyView = findViewById(R.id.empty_print_state);
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700316 mListView.setEmptyView(emptyView);
Svetoslav Ganov24c686b2013-10-05 18:52:06 -0700317 }
Svetoslava798c0a2014-05-15 10:47:19 -0700318 TextView titleView = (TextView) findViewById(R.id.title);
319 View progressBar = findViewById(R.id.progress_bar);
Philip P. Moltmann953639c2015-11-11 15:30:16 -0800320 if (!mHasEnabledPrintServices) {
321 titleView.setText(R.string.print_no_print_services);
322 progressBar.setVisibility(View.GONE);
323 } else if (adapter.getUnfilteredCount() <= 0) {
Svetoslav Ganov264c5662013-10-05 12:58:17 -0700324 titleView.setText(R.string.print_searching_for_printers);
325 progressBar.setVisibility(View.VISIBLE);
326 } else {
327 titleView.setText(R.string.print_no_printers);
328 progressBar.setVisibility(View.GONE);
329 }
330 }
331
Svetoslavebec4682013-10-08 17:17:08 -0700332 private void announceSearchResultIfNeeded() {
Svetoslava798c0a2014-05-15 10:47:19 -0700333 if (AccessibilityManager.getInstance(this).isEnabled()) {
Svetoslavebec4682013-10-08 17:17:08 -0700334 if (mAnnounceFilterResult == null) {
335 mAnnounceFilterResult = new AnnounceFilterResult();
336 }
337 mAnnounceFilterResult.post();
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700338 }
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700339 }
340
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800341 @Override
342 public Loader<List<PrintServiceInfo>> onCreateLoader(int id, Bundle args) {
343 return new PrintServicesLoader((PrintManager) getSystemService(Context.PRINT_SERVICE), this,
344 PrintManager.ENABLED_SERVICES);
345 }
Svetoslav269403b2013-08-14 17:31:04 -0700346
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800347 @Override
348 public void onLoadFinished(Loader<List<PrintServiceInfo>> loader,
349 List<PrintServiceInfo> data) {
350 if (data == null || data.isEmpty()) {
351 mHasEnabledPrintServices = false;
352 } else {
353 mHasEnabledPrintServices = true;
354 }
Svetoslav269403b2013-08-14 17:31:04 -0700355
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800356 onPrintServicesUpdate();
357 }
Svetoslav269403b2013-08-14 17:31:04 -0700358
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800359 @Override
360 public void onLoaderReset(Loader<List<PrintServiceInfo>> loader) {
361 if (!isFinishing()) {
362 onLoadFinished(loader, null);
Svetoslav269403b2013-08-14 17:31:04 -0700363 }
364 }
365
Svetoslava798c0a2014-05-15 10:47:19 -0700366 private final class DestinationAdapter extends BaseAdapter implements Filterable {
Svetoslav269403b2013-08-14 17:31:04 -0700367
368 private final Object mLock = new Object();
369
Svetoslava798c0a2014-05-15 10:47:19 -0700370 private final List<PrinterInfo> mPrinters = new ArrayList<>();
Svetoslav269403b2013-08-14 17:31:04 -0700371
Svetoslava798c0a2014-05-15 10:47:19 -0700372 private final List<PrinterInfo> mFilteredPrinters = new ArrayList<>();
Svetoslav269403b2013-08-14 17:31:04 -0700373
374 private CharSequence mLastSearchString;
375
376 public DestinationAdapter() {
Svetoslava798c0a2014-05-15 10:47:19 -0700377 mPrinterRegistry.setOnPrintersChangeListener(new PrinterRegistry.OnPrintersChangeListener() {
378 @Override
379 public void onPrintersChanged(List<PrinterInfo> printers) {
380 synchronized (mLock) {
381 mPrinters.clear();
382 mPrinters.addAll(printers);
383 mFilteredPrinters.clear();
384 mFilteredPrinters.addAll(printers);
385 if (!TextUtils.isEmpty(mLastSearchString)) {
386 getFilter().filter(mLastSearchString);
387 }
388 }
389 notifyDataSetChanged();
390 }
391
392 @Override
393 public void onPrintersInvalid() {
394 synchronized (mLock) {
395 mPrinters.clear();
396 mFilteredPrinters.clear();
397 }
398 notifyDataSetInvalidated();
399 }
400 });
Svetoslav269403b2013-08-14 17:31:04 -0700401 }
402
403 @Override
404 public Filter getFilter() {
405 return new Filter() {
406 @Override
407 protected FilterResults performFiltering(CharSequence constraint) {
408 synchronized (mLock) {
409 if (TextUtils.isEmpty(constraint)) {
410 return null;
411 }
412 FilterResults results = new FilterResults();
Svetoslava798c0a2014-05-15 10:47:19 -0700413 List<PrinterInfo> filteredPrinters = new ArrayList<>();
Svetoslav269403b2013-08-14 17:31:04 -0700414 String constraintLowerCase = constraint.toString().toLowerCase();
415 final int printerCount = mPrinters.size();
416 for (int i = 0; i < printerCount; i++) {
417 PrinterInfo printer = mPrinters.get(i);
Philip P. Moltmanne58d8ff2016-01-26 10:08:31 -0800418 String description = printer.getDescription();
419 if (printer.getName().toLowerCase().contains(constraintLowerCase)
420 || description != null && description.toLowerCase()
421 .contains(constraintLowerCase)) {
Svetoslav269403b2013-08-14 17:31:04 -0700422 filteredPrinters.add(printer);
423 }
424 }
425 results.values = filteredPrinters;
426 results.count = filteredPrinters.size();
427 return results;
428 }
429 }
430
431 @Override
432 @SuppressWarnings("unchecked")
433 protected void publishResults(CharSequence constraint, FilterResults results) {
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700434 final boolean resultCountChanged;
Svetoslav269403b2013-08-14 17:31:04 -0700435 synchronized (mLock) {
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700436 final int oldPrinterCount = mFilteredPrinters.size();
Svetoslav269403b2013-08-14 17:31:04 -0700437 mLastSearchString = constraint;
438 mFilteredPrinters.clear();
439 if (results == null) {
440 mFilteredPrinters.addAll(mPrinters);
441 } else {
442 List<PrinterInfo> printers = (List<PrinterInfo>) results.values;
443 mFilteredPrinters.addAll(printers);
444 }
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700445 resultCountChanged = (oldPrinterCount != mFilteredPrinters.size());
446 }
447 if (resultCountChanged) {
Svetoslavebec4682013-10-08 17:17:08 -0700448 announceSearchResultIfNeeded();
Svetoslav269403b2013-08-14 17:31:04 -0700449 }
450 notifyDataSetChanged();
451 }
452 };
453 }
454
Svetoslav Ganov264c5662013-10-05 12:58:17 -0700455 public int getUnfilteredCount() {
456 synchronized (mLock) {
457 return mPrinters.size();
458 }
459 }
460
Svetoslav269403b2013-08-14 17:31:04 -0700461 @Override
462 public int getCount() {
463 synchronized (mLock) {
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800464 if (mFilteredPrinters.isEmpty()) {
465 return 0;
466 } else {
467 // Add "add printer" item to the end of the list. If the list is empty there is
468 // a link on the empty view
469 return mFilteredPrinters.size() + 1;
470 }
471 }
472 }
473
474 @Override
475 public int getViewTypeCount() {
476 return 2;
477 }
478
479 @Override
480 public int getItemViewType(int position) {
481 // Use separate view types for the "add printer" item an the items referring to printers
482 if (getItem(position) == null) {
483 return 0;
484 } else {
485 return 1;
Svetoslav269403b2013-08-14 17:31:04 -0700486 }
487 }
488
489 @Override
490 public Object getItem(int position) {
491 synchronized (mLock) {
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800492 if (position < mFilteredPrinters.size()) {
493 return mFilteredPrinters.get(position);
494 } else {
495 // Return null to mark this as the "add printer item"
496 return null;
497 }
Svetoslav269403b2013-08-14 17:31:04 -0700498 }
499 }
500
501 @Override
502 public long getItemId(int position) {
503 return position;
504 }
505
506 @Override
Svetoslava798c0a2014-05-15 10:47:19 -0700507 public View getDropDownView(int position, View convertView, ViewGroup parent) {
Svetoslav269403b2013-08-14 17:31:04 -0700508 return getView(position, convertView, parent);
509 }
510
511 @Override
512 public View getView(int position, View convertView, ViewGroup parent) {
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800513 final PrinterInfo printer = (PrinterInfo) getItem(position);
514
515 // Handle "add printer item"
516 if (printer == null) {
517 if (convertView == null) {
518 convertView = getLayoutInflater().inflate(R.layout.add_printer_list_item,
519 parent, false);
520 }
521
522 return convertView;
523 }
524
Svetoslav269403b2013-08-14 17:31:04 -0700525 if (convertView == null) {
Svetoslava798c0a2014-05-15 10:47:19 -0700526 convertView = getLayoutInflater().inflate(
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700527 R.layout.printer_list_item, parent, false);
Svetoslav269403b2013-08-14 17:31:04 -0700528 }
529
Svetoslav1c664b62013-11-04 12:30:08 -0800530 convertView.setEnabled(isActionable(position));
Svetoslav Ganov69b91e02013-10-07 22:17:30 -0700531
Svetoslava798c0a2014-05-15 10:47:19 -0700532
533 CharSequence title = printer.getName();
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800534 Drawable icon = printer.loadIcon(SelectPrinterActivity.this);
Svetoslav269403b2013-08-14 17:31:04 -0700535
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800536 CharSequence printServiceLabel;
Svetoslav269403b2013-08-14 17:31:04 -0700537 try {
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800538 PackageInfo packageInfo = getPackageManager().getPackageInfo(
539 printer.getId().getServiceName().getPackageName(), 0);
540
541 printServiceLabel = packageInfo.applicationInfo.loadLabel(getPackageManager());
542 } catch (NameNotFoundException e) {
543 printServiceLabel = null;
544 }
545
546 CharSequence description = printer.getDescription();
547
548 CharSequence subtitle;
Philip P. Moltmann5462e882016-01-20 13:55:38 -0800549 if (TextUtils.isEmpty(printServiceLabel)) {
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800550 subtitle = description;
Philip P. Moltmann5462e882016-01-20 13:55:38 -0800551 } else if (TextUtils.isEmpty(description)) {
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800552 subtitle = printServiceLabel;
553 } else {
554 subtitle = getString(R.string.printer_extended_description_template,
555 printServiceLabel, description);
Svetoslav269403b2013-08-14 17:31:04 -0700556 }
557
558 TextView titleView = (TextView) convertView.findViewById(R.id.title);
559 titleView.setText(title);
560
561 TextView subtitleView = (TextView) convertView.findViewById(R.id.subtitle);
562 if (!TextUtils.isEmpty(subtitle)) {
563 subtitleView.setText(subtitle);
564 subtitleView.setVisibility(View.VISIBLE);
565 } else {
566 subtitleView.setText(null);
567 subtitleView.setVisibility(View.GONE);
568 }
569
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800570 LinearLayout moreInfoView = (LinearLayout) convertView.findViewById(R.id.more_info);
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800571 if (printer.getInfoIntent() != null) {
572 moreInfoView.setVisibility(View.VISIBLE);
573 moreInfoView.setOnClickListener(new OnClickListener() {
574 @Override
575 public void onClick(View v) {
576 try {
Philip P. Moltmann443075a2016-01-26 13:04:21 -0800577 startIntentSender(printer.getInfoIntent().getIntentSender(), null, 0, 0,
578 0);
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800579 } catch (SendIntentException e) {
580 Log.e(LOG_TAG, "Could not execute pending info intent: %s", e);
581 }
582 }
583 });
Philip P. Moltmann443075a2016-01-26 13:04:21 -0800584 } else {
585 moreInfoView.setVisibility(View.GONE);
Philip P. Moltmannbb9f6862015-12-01 14:44:24 -0800586 }
Svetoslav39e71de2013-10-02 19:30:32 -0700587
588 ImageView iconView = (ImageView) convertView.findViewById(R.id.icon);
589 if (icon != null) {
Svetoslav39e71de2013-10-02 19:30:32 -0700590 iconView.setVisibility(View.VISIBLE);
Philip P. Moltmann443075a2016-01-26 13:04:21 -0800591 if (!isActionable(position)) {
592 icon.mutate();
593
594 TypedValue value = new TypedValue();
595 getTheme().resolveAttribute(android.R.attr.disabledAlpha, value, true);
596 icon.setAlpha((int)(value.getFloat() * 255));
597 }
598 iconView.setImageDrawable(icon);
Svetoslav39e71de2013-10-02 19:30:32 -0700599 } else {
600 iconView.setVisibility(View.GONE);
601 }
602
Svetoslav269403b2013-08-14 17:31:04 -0700603 return convertView;
604 }
605
Svetoslav1c664b62013-11-04 12:30:08 -0800606 public boolean isActionable(int position) {
Svetoslav Ganov69b91e02013-10-07 22:17:30 -0700607 PrinterInfo printer = (PrinterInfo) getItem(position);
Philip P. Moltmann66c96592016-02-24 11:32:43 -0800608
609 if (printer == null) {
610 return true;
611 } else {
612 return printer.getStatus() != PrinterInfo.STATUS_UNAVAILABLE;
613 }
Svetoslav Ganov69b91e02013-10-07 22:17:30 -0700614 }
Svetoslav269403b2013-08-14 17:31:04 -0700615 }
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700616
617 private final class AnnounceFilterResult implements Runnable {
618 private static final int SEARCH_RESULT_ANNOUNCEMENT_DELAY = 1000; // 1 sec
619
620 public void post() {
621 remove();
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700622 mListView.postDelayed(this, SEARCH_RESULT_ANNOUNCEMENT_DELAY);
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700623 }
624
625 public void remove() {
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700626 mListView.removeCallbacks(this);
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700627 }
628
629 @Override
630 public void run() {
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700631 final int count = mListView.getAdapter().getCount();
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700632 final String text;
633 if (count <= 0) {
634 text = getString(R.string.print_no_printers);
635 } else {
Svetoslava798c0a2014-05-15 10:47:19 -0700636 text = getResources().getQuantityString(
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700637 R.plurals.print_search_result_count_utterance, count, count);
638 }
Svetoslav Ganoved513d7e2013-10-17 09:53:05 -0700639 mListView.announceForAccessibility(text);
Svetoslav Ganov56ddf1f2013-10-05 19:55:49 -0700640 }
641 }
Svetoslav269403b2013-08-14 17:31:04 -0700642}