summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSvetoslav <svetoslavganov@google.com>2013-08-14 07:09:25 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-08-14 07:09:25 +0000
commit59703c7186ea49669e7dd326a1e2e704385cbaff (patch)
tree9e83f12db6224b33db3799e459ce10444645a003
parent3dfa5eb9d9eeb12d761194cb06dc1ba63ed61e95 (diff)
parent66160bb881470a691005c8ad4e9c31c41fd5f810 (diff)
downloadframeworks_base-59703c7186ea49669e7dd326a1e2e704385cbaff.zip
frameworks_base-59703c7186ea49669e7dd326a1e2e704385cbaff.tar.gz
frameworks_base-59703c7186ea49669e7dd326a1e2e704385cbaff.tar.bz2
Merge "Partial implementation for the favorite and available printer tracking." into klp-dev
-rw-r--r--packages/PrintSpooler/AndroidManifest.xml6
-rw-r--r--packages/PrintSpooler/res/layout/choose_printer_activity.xml23
-rw-r--r--packages/PrintSpooler/res/menu/choose_printer_activity.xml29
-rw-r--r--packages/PrintSpooler/res/values/strings.xml5
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/AvailablePrinterProvider.java285
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ChoosePrinterActivity.java28
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/DataLoader.java33
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/DataProvider.java50
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/FavoritePrinterProvider.java364
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java405
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java20
-rw-r--r--services/java/com/android/server/print/RemotePrintService.java1
12 files changed, 959 insertions, 290 deletions
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 74fd7a8..c00639d 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -50,6 +50,12 @@
android:theme="@style/PrintJobConfigActivityTheme">
</activity>
+ <activity
+ android:name=".ChoosePrinterActivity"
+ android:exported="false"
+ android:theme="@android:style/Theme.Holo.Light">
+ </activity>
+
<receiver
android:name=".NotificationController$NotificationBroadcastReceiver"
android:exported="false" >
diff --git a/packages/PrintSpooler/res/layout/choose_printer_activity.xml b/packages/PrintSpooler/res/layout/choose_printer_activity.xml
new file mode 100644
index 0000000..c34a108
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/choose_printer_activity.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/list_view"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+</ListView>
+
diff --git a/packages/PrintSpooler/res/menu/choose_printer_activity.xml b/packages/PrintSpooler/res/menu/choose_printer_activity.xml
new file mode 100644
index 0000000..3774279
--- /dev/null
+++ b/packages/PrintSpooler/res/menu/choose_printer_activity.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >
+
+ <item
+ android:id="@+id/action_search"
+ android:title="@string/search"
+ android:icon="@*android:drawable/ic_menu_search_holo_light"
+ android:actionViewClass="android.widget.SearchView"
+ android:showAsAction="ifRoom"
+ android:alphabeticShortcut="f"
+ android:imeOptions="actionSearch">
+ </item>
+
+</menu>
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 2086f58..1cd611f 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -58,6 +58,11 @@
<!-- Title for the temporary dialog show while an app is generating a print job. [CHAR LIMIT=30] -->
<string name="generating_print_job">Generating print job</string>
+ <!-- Choose printer activity -->
+
+ <!-- Title for the share action bar menu item. [CHAR LIMIT=20] -->
+ <string name="search">Search</string>
+
<!-- Notifications -->
<!-- Template for the notificaiton label for a printing print job. [CHAR LIMIT=25] -->
diff --git a/packages/PrintSpooler/src/com/android/printspooler/AvailablePrinterProvider.java b/packages/PrintSpooler/src/com/android/printspooler/AvailablePrinterProvider.java
new file mode 100644
index 0000000..658a224
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/AvailablePrinterProvider.java
@@ -0,0 +1,285 @@
+/*
+ * 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.printspooler;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.print.IPrinterDiscoverySessionController;
+import android.print.IPrinterDiscoverySessionObserver;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class is responsible to provide the available printers.
+ * It starts and stops printer discovery and manages the returned
+ * printers.
+ */
+public class AvailablePrinterProvider extends DataProvider<PrinterInfo>
+ implements DataLoader {
+ private static final String LOG_TAG = "AvailablePrinterProvider";
+
+ private final Set<PrinterId> mPrinteIdsSet = new ArraySet<PrinterId>();
+
+ private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
+
+ private final List<PrinterId> mPriorityList;
+
+ private PrinterDiscoverySession mDiscoverySession;
+
+ public AvailablePrinterProvider(Context context, List<PrinterId> priorityList) {
+ mDiscoverySession = new PrinterDiscoverySession(context.getMainLooper());
+ mPriorityList = priorityList;
+ }
+
+ @Override
+ public void startLoadData() {
+ mDiscoverySession.open();
+ }
+
+ @Override
+ public void stopLoadData() {
+ mDiscoverySession.close();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mPrinters.size();
+ }
+
+ @Override
+ public int getItemIndex(PrinterInfo printer) {
+ return mPrinters.indexOf(printer);
+ }
+
+ @Override
+ public PrinterInfo getItemAt(int index) {
+ return mPrinters.get(index);
+ }
+
+ public void refreshItem(int index) {
+ PrinterInfo printer = getItemAt(index);
+ mDiscoverySession.requestPrinterUpdate(printer.getId());
+ }
+
+ private void addPrinters(List<PrinterInfo> printers) {
+ boolean addedPrinters = false;
+
+ final int addedPrinterCount = printers.size();
+ for (int i = 0; i < addedPrinterCount; i++) {
+ PrinterInfo addedPrinter = printers.get(i);
+ if (mPrinteIdsSet.add(addedPrinter.getId())) {
+ mPrinters.add(addedPrinter);
+ addedPrinters = true;
+ }
+ }
+
+ if (addedPrinters) {
+ notifyChanged();
+ }
+ }
+
+ private void updatePrinters(List<PrinterInfo> printers) {
+ boolean updatedPrinters = false;
+
+ final int updatedPrinterCount = printers.size();
+ for (int i = 0; i < updatedPrinterCount; i++) {
+ PrinterInfo updatedPrinter = printers.get(i);
+ if (mPrinteIdsSet.contains(updatedPrinter.getId())) {
+ final int oldPrinterCount = mPrinters.size();
+ for (int j = 0; j < oldPrinterCount; j++) {
+ PrinterInfo oldPrinter = mPrinters.get(j);
+ if (updatedPrinter.getId().equals(oldPrinter.getId())) {
+ mPrinters.set(j, updatedPrinter);
+ updatedPrinters = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (updatedPrinters) {
+ notifyChanged();
+ }
+ }
+
+ private void removePrinters(List<PrinterId> printers) {
+ boolean removedPrinters = false;
+
+ final int removedPrinterCount = printers.size();
+ for (int i = 0; i < removedPrinterCount; i++) {
+ PrinterId removedPrinter = printers.get(i);
+ if (mPrinteIdsSet.contains(removedPrinter)) {
+ mPrinteIdsSet.remove(removedPrinter);
+ Iterator<PrinterInfo> iterator = mPrinters.iterator();
+ while (iterator.hasNext()) {
+ PrinterInfo oldPrinter = iterator.next();
+ if (removedPrinter.equals(oldPrinter.getId())) {
+ iterator.remove();
+ break;
+ }
+ }
+ }
+ }
+
+ if (removedPrinters) {
+ notifyChanged();
+ }
+ }
+
+ private final class PrinterDiscoverySession {
+
+ private final Handler mHandler;
+
+ private final IPrinterDiscoverySessionObserver mObserver;
+
+ private IPrinterDiscoverySessionController mController;
+
+ public PrinterDiscoverySession(Looper looper) {
+ mHandler = new SessionHandler(looper);
+ mObserver = new PrinterDiscoverySessionObserver(this);
+ }
+
+ public void open() {
+ PrintSpooler.peekInstance().createPrinterDiscoverySession(
+ mObserver);
+ }
+
+ public void close() {
+ if (mController != null) {
+ try {
+ mController.close();
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error closing printer discovery session", re);
+ } finally {
+ mController = null;
+ }
+ }
+ }
+
+ public void requestPrinterUpdate(PrinterId printerId) {
+ if (mController != null) {
+ try {
+ mController.requestPrinterUpdate(printerId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error requesting printer udpdate", re);
+ }
+ }
+ }
+
+ private final class SessionHandler extends Handler {
+ public static final int MSG_SET_CONTROLLER = 1;
+ public static final int MSG_ON_PRINTERS_ADDED = 2;
+ public static final int MSG_ON_PRINTERS_REMOVED = 3;
+ public static final int MSG_ON_PRINTERS_UPDATED = 4;
+
+ public SessionHandler(Looper looper) {
+ super(looper, null, false);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_SET_CONTROLLER: {
+ mController = (IPrinterDiscoverySessionController) message.obj;
+ try {
+ mController.open(mPriorityList);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, "Error starting printer discovery");
+ }
+ } break;
+
+ case MSG_ON_PRINTERS_ADDED: {
+ List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
+ addPrinters(printers);
+ } break;
+
+ case MSG_ON_PRINTERS_REMOVED: {
+ List<PrinterId> printers = (List<PrinterId>) message.obj;
+ removePrinters(printers);
+ } break;
+
+ case MSG_ON_PRINTERS_UPDATED: {
+ List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
+ updatePrinters(printers);
+ } break;
+ };
+ }
+ }
+ }
+
+ private static final class PrinterDiscoverySessionObserver
+ extends IPrinterDiscoverySessionObserver.Stub {
+
+ private final WeakReference<PrinterDiscoverySession> mWeakSession;
+
+ public PrinterDiscoverySessionObserver(PrinterDiscoverySession session) {
+ mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
+ }
+
+ @Override
+ public void setController(IPrinterDiscoverySessionController controller) {
+ PrinterDiscoverySession sesison = mWeakSession.get();
+ if (sesison != null) {
+ sesison.mHandler.obtainMessage(
+ PrinterDiscoverySession.SessionHandler.MSG_SET_CONTROLLER,
+ controller).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onPrintersAdded(List<PrinterInfo> printers) {
+ PrinterDiscoverySession sesison = mWeakSession.get();
+ if (sesison != null) {
+ sesison.mHandler.obtainMessage(
+ PrinterDiscoverySession.SessionHandler.MSG_ON_PRINTERS_ADDED,
+ printers).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onPrintersRemoved(List<PrinterId> printers) {
+ PrinterDiscoverySession session = mWeakSession.get();
+ if (session != null) {
+ session.mHandler.obtainMessage(
+ PrinterDiscoverySession.SessionHandler.MSG_ON_PRINTERS_REMOVED,
+ printers).sendToTarget();
+ }
+ }
+
+ @Override
+ public void onPrintersUpdated(List<PrinterInfo> printers) {
+ PrinterDiscoverySession session = mWeakSession.get();
+ if (session != null) {
+ session.mHandler.obtainMessage(
+ PrinterDiscoverySession.SessionHandler.MSG_ON_PRINTERS_UPDATED,
+ printers).sendToTarget();
+ }
+ }
+ };
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ChoosePrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ChoosePrinterActivity.java
new file mode 100644
index 0000000..8b0dd66
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/ChoosePrinterActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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.printspooler;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class ChoosePrinterActivity extends Activity {
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ setContentView(R.layout.choose_printer_activity);
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/DataLoader.java b/packages/PrintSpooler/src/com/android/printspooler/DataLoader.java
new file mode 100644
index 0000000..82cc2e1
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/DataLoader.java
@@ -0,0 +1,33 @@
+/*
+ * 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.printspooler;
+
+/**
+ * This is the contract for a class that know how to load data.
+ */
+public interface DataLoader {
+
+ /**
+ * Requests to start loading data.
+ */
+ public void startLoadData();
+
+ /**
+ * Requests to stop loading data.
+ */
+ public void stopLoadData();
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/DataProvider.java b/packages/PrintSpooler/src/com/android/printspooler/DataProvider.java
new file mode 100644
index 0000000..7b10903
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/DataProvider.java
@@ -0,0 +1,50 @@
+/*
+ * 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.printspooler;
+
+import android.database.DataSetObservable;
+
+/**
+ * This is the simple contract for data providers.
+ *
+ * @param <T> The type of the providers data.
+ */
+public abstract class DataProvider<T> extends DataSetObservable {
+
+ /**
+ * Gets the number of items.
+ *
+ * @return The item count.
+ */
+ public abstract int getItemCount();
+
+ /**
+ * Gets the index of an item.
+ *
+ * @param item The item.
+ * @return The item index.
+ */
+ public abstract int getItemIndex(T item);
+
+ /**
+ * Gets an item at a given position.
+ *
+ * @param index The position.
+ * @return The item.
+ */
+ public abstract T getItemAt(int index);
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/FavoritePrinterProvider.java b/packages/PrintSpooler/src/com/android/printspooler/FavoritePrinterProvider.java
new file mode 100644
index 0000000..2c539d1
--- /dev/null
+++ b/packages/PrintSpooler/src/com/android/printspooler/FavoritePrinterProvider.java
@@ -0,0 +1,364 @@
+/*
+ * 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.printspooler;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class provides the favorite printers based on past usage.
+ */
+final class FavoritePrinterProvider extends DataProvider<PrinterInfo> implements DataLoader {
+
+ private static final String LOG_TAG = "FavoritePrinterProvider";
+
+ private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
+
+ private static final int MAX_HISTORY_LENGTH = 50;
+
+ private static final double WEIGHT_DECAY_COEFFICIENT = 0.95f;
+
+ private final List<PrinterRecord> mHistoricalPrinters = new ArrayList<PrinterRecord>();
+
+ private final List<PrinterRecord> mFavoritePrinters = new ArrayList<PrinterRecord>();
+
+ private final PersistenceManager mPersistenceManager;
+
+ public FavoritePrinterProvider(Context context) {
+ mPersistenceManager = new PersistenceManager(context);
+ }
+
+ public void addPrinter(PrinterInfo printer) {
+ addPrinterInternal(printer);
+ computeFavoritePrinters();
+ mPersistenceManager.writeState();
+ }
+
+ @Override
+ public int getItemCount() {
+ return mFavoritePrinters.size();
+ }
+
+ @Override
+ public PrinterInfo getItemAt(int index) {
+ return mFavoritePrinters.get(index).printer;
+ }
+
+ @Override
+ public int getItemIndex(PrinterInfo printer) {
+ return mFavoritePrinters.indexOf(printer);
+ }
+
+ @Override
+ public void startLoadData() {
+ mPersistenceManager.readStateLocked();
+ computeFavoritePrinters();
+ }
+
+ @Override
+ public void stopLoadData() {
+ /* do nothing */
+ }
+
+ private void addPrinterInternal(PrinterInfo printer) {
+ if (mHistoricalPrinters.size() >= MAX_HISTORY_LENGTH) {
+ mHistoricalPrinters.remove(0);
+ }
+ mHistoricalPrinters.add(new PrinterRecord(printer));
+ }
+
+ private void computeFavoritePrinters() {
+ Map<PrinterId, PrinterRecord> recordMap =
+ new ArrayMap<PrinterId, PrinterRecord>();
+
+ // Recompute the weights.
+ float currentWeight = 1.0f;
+ final int printerCount = mHistoricalPrinters.size();
+ for (int i = printerCount - 1; i >= 0; i--) {
+ PrinterRecord record = mHistoricalPrinters.get(i);
+ record.weight = currentWeight;
+ // Aggregate weight for the same printer
+ PrinterRecord oldRecord = recordMap.put(record.printer.getId(), record);
+ if (oldRecord != null) {
+ record.weight += oldRecord.weight;
+ }
+ currentWeight *= WEIGHT_DECAY_COEFFICIENT;
+ }
+
+ // Copy the unique printer records with computed weights.
+ mFavoritePrinters.addAll(recordMap.values());
+
+ // Soft the favorite printers.
+ Collections.sort(mFavoritePrinters);
+ }
+
+ private final class PrinterRecord implements Comparable<PrinterRecord> {
+ public final PrinterInfo printer;
+ public float weight;
+
+ public PrinterRecord(PrinterInfo printer) {
+ this.printer = printer;
+ }
+
+ @Override
+ public int compareTo(PrinterRecord another) {
+ return Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
+ }
+ }
+
+ private final class PersistenceManager {
+ private static final String PERSIST_FILE_NAME = "printer_history.xml";
+
+ private static final String TAG_PRINTERS = "printers";
+
+ private static final String TAG_PRINTER = "printer";
+ private static final String TAG_PRINTER_ID = "printerId";
+
+ private static final String ATTR_LOCAL_ID = "localId";
+ private static final String ATTR_SERVICE_NAME = "serviceName";
+
+ private static final String ATTR_NAME = "name";
+ private static final String ATTR_DESCRIPTION = "description";
+ private static final String ATTR_STATUS = "status";
+
+ private final AtomicFile mStatePersistFile;
+
+ private PersistenceManager(Context context) {
+ mStatePersistFile = new AtomicFile(new File(context.getFilesDir(),
+ PERSIST_FILE_NAME));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void writeState() {
+
+ new AsyncTask<List<PrinterRecord>, Void, Void>() {
+ @Override
+ protected Void doInBackground(List<PrinterRecord>... printers) {
+ doWriteState(printers[0]);
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ notifyChanged();
+ }
+
+ }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR,
+ new ArrayList<PrinterRecord>(mHistoricalPrinters));
+ }
+
+ private void doWriteState(List<PrinterRecord> printers) {
+ FileOutputStream out = null;
+ try {
+ out = mStatePersistFile.startWrite();
+
+ XmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(out, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.startTag(null, TAG_PRINTERS);
+
+ final int printerCount = printers.size();
+ for (int i = printerCount - 1; i >= 0; i--) {
+ PrinterInfo printer = printers.get(i).printer;
+
+ serializer.startTag(null, TAG_PRINTER);
+
+ serializer.attribute(null, ATTR_NAME, printer.getName());
+ serializer.attribute(null, ATTR_STATUS, String.valueOf(printer.getStatus()));
+ String description = printer.getDescription();
+ if (description != null) {
+ serializer.attribute(null, ATTR_DESCRIPTION, description);
+ }
+
+ PrinterId printerId = printer.getId();
+ serializer.startTag(null, TAG_PRINTER_ID);
+ serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
+ serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
+ .flattenToString());
+ serializer.endTag(null, TAG_PRINTER_ID);
+
+ serializer.endTag(null, TAG_PRINTER);
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[PERSISTED] " + printer);
+ }
+ }
+
+ serializer.endTag(null, TAG_PRINTERS);
+ serializer.endDocument();
+ mStatePersistFile.finishWrite(out);
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[PERSIST END]");
+ }
+ } catch (IOException ioe) {
+ Slog.w(LOG_TAG, "Failed to write printer history, restoring backup.", ioe);
+ mStatePersistFile.failWrite(out);
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+
+ public void readStateLocked() {
+ FileInputStream in = null;
+ try {
+ in = mStatePersistFile.openRead();
+ } catch (FileNotFoundException e) {
+ Log.i(LOG_TAG, "No existing printer history.");
+ return;
+ }
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(in, null);
+ parseState(parser);
+ } catch (IllegalStateException ise) {
+ Slog.w(LOG_TAG, "Failed parsing ", ise);
+ } catch (NullPointerException npe) {
+ Slog.w(LOG_TAG, "Failed parsing ", npe);
+ } catch (NumberFormatException nfe) {
+ Slog.w(LOG_TAG, "Failed parsing ", nfe);
+ } catch (XmlPullParserException xppe) {
+ Slog.w(LOG_TAG, "Failed parsing ", xppe);
+ } catch (IOException ioe) {
+ Slog.w(LOG_TAG, "Failed parsing ", ioe);
+ } catch (IndexOutOfBoundsException iobe) {
+ Slog.w(LOG_TAG, "Failed parsing ", iobe);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ notifyChanged();
+ }
+
+ private void parseState(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ parser.next();
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.START_TAG, TAG_PRINTERS);
+ parser.next();
+
+ while (parsePrinter(parser)) {
+ parser.next();
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_PRINTERS);
+
+ // We were reading the new records first and appended them first,
+ // hence the historical list is in a reversed order, so fix that.
+ Collections.reverse(mHistoricalPrinters);
+ }
+
+ private boolean parsePrinter(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ skipEmptyTextTags(parser);
+ if (!accept(parser, XmlPullParser.START_TAG, TAG_PRINTER)) {
+ return false;
+ }
+
+ String name = parser.getAttributeValue(null, ATTR_NAME);
+ String description = parser.getAttributeValue(null, ATTR_DESCRIPTION);
+ final int status = Integer.parseInt(parser.getAttributeValue(null, ATTR_STATUS));
+
+ parser.next();
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID);
+ String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
+ ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
+ null, ATTR_SERVICE_NAME));
+ PrinterId printerId = new PrinterId(service, localId);
+ parser.next();
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_PRINTER_ID);
+ parser.next();
+
+ PrinterInfo.Builder builder = new PrinterInfo.Builder(printerId, name, status);
+ builder.setDescription(description);
+ PrinterInfo printer = builder.create();
+
+ addPrinterInternal(printer);
+
+ if (DEBUG) {
+ Log.i(LOG_TAG, "[RESTORED] " + printer);
+ }
+
+ skipEmptyTextTags(parser);
+ expect(parser, XmlPullParser.END_TAG, TAG_PRINTER);
+
+ return true;
+ }
+
+ private void expect(XmlPullParser parser, int type, String tag)
+ throws IOException, XmlPullParserException {
+ if (!accept(parser, type, tag)) {
+ throw new XmlPullParserException("Exepected event: " + type
+ + " and tag: " + tag + " but got event: " + parser.getEventType()
+ + " and tag:" + parser.getName());
+ }
+ }
+
+ private void skipEmptyTextTags(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ while (accept(parser, XmlPullParser.TEXT, null)
+ && "\n".equals(parser.getText())) {
+ parser.next();
+ }
+ }
+
+ private boolean accept(XmlPullParser parser, int type, String tag)
+ throws IOException, XmlPullParserException {
+ if (parser.getEventType() != type) {
+ return false;
+ }
+ if (tag != null) {
+ if (!tag.equals(parser.getName())) {
+ return false;
+ }
+ } else if (parser.getName() != null) {
+ return false;
+ }
+ return true;
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 9160b7d..f8e9f43 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.DataSetObserver;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -34,8 +35,6 @@ import android.os.Message;
import android.os.RemoteException;
import android.print.ILayoutResultCallback;
import android.print.IPrintDocumentAdapter;
-import android.print.IPrinterDiscoverySessionController;
-import android.print.IPrinterDiscoverySessionObserver;
import android.print.IWriteResultCallback;
import android.print.PageRange;
import android.print.PrintAttributes;
@@ -64,6 +63,7 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;
@@ -72,7 +72,6 @@ import android.widget.TextView;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
@@ -132,11 +131,13 @@ public class PrintJobConfigActivity extends Activity {
}
};
- private PrintSpooler mSpooler;
private Editor mEditor;
private Document mDocument;
private PrintController mController;
- private PrinterDiscoverySessionObserver mPrinterDiscoverySessionObserver;
+
+ private AvailablePrinterProvider mAvailablePrinters;
+
+ private FavoritePrinterProvider mFavoritePrinters;
private int mPrintJobId;
@@ -168,12 +169,15 @@ public class PrintJobConfigActivity extends Activity {
mCurrPrintAttributes.copyFrom(attributes);
}
- mSpooler = PrintSpooler.peekInstance();
+ // TODO: Use history
+ mAvailablePrinters = new AvailablePrinterProvider(this, null);
+ mFavoritePrinters = new FavoritePrinterProvider(this);
+
mEditor = new Editor();
mDocument = new Document();
mController = new PrintController(new RemotePrintDocumentAdapter(
IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
- mSpooler.generateFileForPrintJob(mPrintJobId)));
+ PrintSpooler.peekInstance().generateFileForPrintJob(mPrintJobId)));
try {
mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
@@ -184,9 +188,26 @@ public class PrintJobConfigActivity extends Activity {
mController.initialize();
mEditor.initialize();
- mPrinterDiscoverySessionObserver = new PrinterDiscoverySessionObserver(mEditor,
- getMainLooper());
- mSpooler.createPrinterDiscoverySession(mPrinterDiscoverySessionObserver);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // TODO: Polish this
+ if (!mEditor.isPrintConfirmed()) {
+ mAvailablePrinters.startLoadData();
+ mFavoritePrinters.startLoadData();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ // TODO: Polish this
+ if (!mEditor.isPrintConfirmed()) {
+ mAvailablePrinters.stopLoadData();
+ mFavoritePrinters.stopLoadData();
+ }
+ super.onPause();
}
@Override
@@ -194,17 +215,14 @@ public class PrintJobConfigActivity extends Activity {
// We can safely do the work in here since at this point
// the system is bound to our (spooler) process which
// guarantees that this process will not be killed.
- mPrinterDiscoverySessionObserver.close();
- mPrinterDiscoverySessionObserver.destroy();
- mPrinterDiscoverySessionObserver = null;
if (mController.hasStarted()) {
mController.finish();
}
if (mEditor.isPrintConfirmed() && mController.isFinished()) {
- mSpooler.setPrintJobState(mPrintJobId,
+ PrintSpooler.peekInstance().setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_QUEUED, null);
} else {
- mSpooler.setPrintJobState(mPrintJobId,
+ PrintSpooler.peekInstance().setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_CANCELED, null);
}
mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
@@ -320,7 +338,8 @@ public class PrintJobConfigActivity extends Activity {
// completed and nothing changed, so we handle writing as usual.
handleOnLayoutFinished(mDocument.info, false, mRequestCounter.get());
} else {
- mSpooler.setPrintJobAttributesNoPersistence(mPrintJobId, mCurrPrintAttributes);
+ PrintSpooler.peekInstance().setPrintJobAttributesNoPersistence(mPrintJobId,
+ mCurrPrintAttributes);
mMetadata.putBoolean(PrintDocumentAdapter.METADATA_KEY_PRINT_PREVIEW,
!mEditor.isPrintConfirmed());
@@ -353,15 +372,14 @@ public class PrintJobConfigActivity extends Activity {
}
mControllerState = CONTROLLER_STATE_LAYOUT_COMPLETED;
+ mEditor.updateUi();
- // If the info changed, we update the document and the print job,
- // and update the UI since the the page range selection may have
- // become invalid.
+ // If the info changed, we update the document and the print job.
final boolean infoChanged = !info.equals(mDocument.info);
if (infoChanged) {
mDocument.info = info;
- mSpooler.setPrintJobPrintDocumentInfoNoPersistence(mPrintJobId, info);
- mEditor.updateUi();
+ PrintSpooler.peekInstance().setPrintJobPrintDocumentInfoNoPersistence(
+ mPrintJobId, info);
}
// If the document info or the layout changed, then
@@ -447,11 +465,13 @@ public class PrintJobConfigActivity extends Activity {
if (Arrays.equals(mDocument.pages, mRequestedPages)) {
// We got a document with exactly the pages we wanted. Hence,
// the printer has to print all pages in the data.
- mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, ALL_PAGES_ARRAY);
+ PrintSpooler.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
+ ALL_PAGES_ARRAY);
} else if (Arrays.equals(mDocument.pages, ALL_PAGES_ARRAY)) {
// We requested specific pages but got all of them. Hence,
// the printer has to print only the requested pages.
- mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, mRequestedPages);
+ PrintSpooler.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
+ mRequestedPages);
} else if (PageRangeUtils.contains(mDocument.pages, mRequestedPages)) {
// We requested specific pages and got more but not all pages.
// Hence, we have to offset appropriately the printed pages to
@@ -460,14 +480,16 @@ public class PrintJobConfigActivity extends Activity {
final int offset = mDocument.pages[0].getStart() - pages[0].getStart();
PageRange[] offsetPages = Arrays.copyOf(mDocument.pages, mDocument.pages.length);
PageRangeUtils.offsetStart(offsetPages, offset);
- mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, offsetPages);
+ PrintSpooler.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
+ offsetPages);
} else if (Arrays.equals(mRequestedPages, ALL_PAGES_ARRAY)
&& mDocument.pages.length == 1 && mDocument.pages[0].getStart() == 0
&& mDocument.pages[0].getEnd() == mDocument.info.getPageCount() - 1) {
// We requested all pages via the special constant and got all
// of them as an explicit enumeration. Hence, the printer has
// to print only the requested pages.
- mSpooler.setPrintJobPagesNoPersistence(mPrintJobId, mDocument.pages);
+ PrintSpooler.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
+ mDocument.pages);
} else {
// We did not get the pages we requested, then the application
// misbehaves, so we fail quickly.
@@ -592,7 +614,7 @@ public class PrintJobConfigActivity extends Activity {
private final EditText mRangeEditText;
private final Spinner mDestinationSpinner;
- private final ArrayAdapter<SpinnerItem<PrinterInfo>> mDestinationSpinnerAdapter;
+ private final DestinationAdapter mDestinationSpinnerAdapter;
private final Spinner mMediaSizeSpinner;
private final ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
@@ -623,15 +645,18 @@ public class PrintJobConfigActivity extends Activity {
return;
}
mCurrPrintAttributes.clear();
- SpinnerItem<PrinterInfo> dstItem = mDestinationSpinnerAdapter.getItem(position);
- if (dstItem != null) {
- PrinterInfo printer = dstItem.value;
- mSpooler.setPrintJobPrinterNoPersistence(mPrintJobId, printer);
+ PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter
+ .getItem(position);
+ if (printer != null) {
+ PrintSpooler.peekInstance().setPrintJobPrinterNoPersistence(
+ mPrintJobId, printer);
PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
if (capabilities == null) {
List<PrinterId> printerIds = new ArrayList<PrinterId>();
printerIds.add(printer.getId());
- mPrinterDiscoverySessionObserver.requestPrinterUpdate(printer.getId());
+ final int index = mAvailablePrinters.getItemIndex(printer);
+ mAvailablePrinters.refreshItem(index);
+ mWaitingForPrinterCapabilities = true;
//TODO: We need a timeout for the update.
} else {
capabilities.getDefaults(mCurrPrintAttributes);
@@ -728,7 +753,7 @@ public class PrintJobConfigActivity extends Activity {
}
mCopiesEditText.setError(null);
- mSpooler.setPrintJobCopiesNoPersistence(mPrintJobId, copies);
+ PrintSpooler.peekInstance().setPrintJobCopiesNoPersistence(mPrintJobId, copies);
updateUi();
if (hadErrors && !hasErrors() && printAttributesChanged()) {
@@ -805,6 +830,8 @@ public class PrintJobConfigActivity extends Activity {
private boolean mIgnoreNextCopiesChange;
private boolean mIgnoreNextRangeChange;
+ private boolean mWaitingForPrinterCapabilities;
+
public Editor() {
// Content container
mContentContainer = findViewById(R.id.content_container);
@@ -812,13 +839,40 @@ public class PrintJobConfigActivity extends Activity {
// Copies
mCopiesEditText = (EditText) findViewById(R.id.copies_edittext);
mCopiesEditText.setText(String.valueOf(MIN_COPIES));
- mSpooler.setPrintJobCopiesNoPersistence(mPrintJobId, MIN_COPIES);
+ PrintSpooler.peekInstance().setPrintJobCopiesNoPersistence(mPrintJobId, MIN_COPIES);
mCopiesEditText.addTextChangedListener(mCopiesTextWatcher);
mCopiesEditText.selectAll();
// Destination.
+ mDestinationSpinnerAdapter = new DestinationAdapter(mAvailablePrinters);
+ mDestinationSpinnerAdapter.registerDataSetObserver(new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ // Maybe we did not have capabilities when the current printer was
+ // selected, but now the selected printer has capabilities. Generate
+ // a fake selection so the code in the selection change handling takes
+ // care of updating everything. This way the logic is in one place.
+ if (mWaitingForPrinterCapabilities) {
+ mWaitingForPrinterCapabilities = false;
+ PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
+ if (printer != null) {
+ if (printer.getCapabilities() != null) {
+ final int selectedPosition =
+ mDestinationSpinner.getSelectedItemPosition();
+ mOnItemSelectedListener.onItemSelected(mDestinationSpinner, null,
+ selectedPosition, selectedPosition);
+ }
+ }
+ }
+ updateUi();
+ }
+
+ @Override
+ public void onInvalidated() {
+ updateUi();
+ }
+ });
mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
- mDestinationSpinnerAdapter = new DestinationAdapter();
mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
@@ -877,7 +931,6 @@ public class PrintJobConfigActivity extends Activity {
@Override
public void onClick(View v) {
mEditor.confirmPrint();
- updateUi();
mController.update();
showGeneratingPrintJobUi();
}
@@ -1001,6 +1054,11 @@ public class PrintJobConfigActivity extends Activity {
public void confirmPrint() {
mEditorState = EDITOR_STATE_CONFIRMED_PRINT;
+ PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
+ if (printer != null) {
+ mFavoritePrinters.addPrinter(printer);
+ }
+ updateUi();
}
public boolean isPreviewConfirmed() {
@@ -1063,8 +1121,8 @@ public class PrintJobConfigActivity extends Activity {
final int selectedIndex = mDestinationSpinner.getSelectedItemPosition();
- if (selectedIndex < 0 || mDestinationSpinnerAdapter.getItem(
- selectedIndex).value.getCapabilities() == null) {
+ if (selectedIndex < 0 || ((PrinterInfo) mDestinationSpinnerAdapter.getItem(
+ selectedIndex)).getCapabilities() == null) {
// Destination
mDestinationSpinner.setEnabled(false);
@@ -1121,16 +1179,12 @@ public class PrintJobConfigActivity extends Activity {
mPrintButton.setEnabled(false);
} else {
PrintAttributes defaultAttributes = mTempPrintAttributes;
- PrinterInfo printer = mDestinationSpinnerAdapter.getItem(selectedIndex).value;
+ PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
printer.getCapabilities().getDefaults(defaultAttributes);
// Destination
- if (mDestinationSpinnerAdapter.getCount() > 1) {
- mDestinationSpinner.setEnabled(true);
- } else {
- mDestinationSpinner.setEnabled(false);
- }
+ mDestinationSpinner.setEnabled(true);
// Copies
mCopiesEditText.setEnabled(true);
@@ -1159,9 +1213,6 @@ public class PrintJobConfigActivity extends Activity {
if (mediaSizeCount <= 0) {
mMediaSizeSpinner.setEnabled(false);
mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
- } else if (mediaSizeCount == 1) {
- mMediaSizeSpinner.setEnabled(false);
- mMediaSizeSpinner.setSelection(0);
} else {
mMediaSizeSpinner.setEnabled(true);
final int selectedMediaSizeIndex = Math.max(mediaSizes.indexOf(
@@ -1210,9 +1261,6 @@ public class PrintJobConfigActivity extends Activity {
if (colorModeCount <= 0) {
mColorModeSpinner.setEnabled(false);
mColorModeSpinner.setSelection(AdapterView.INVALID_POSITION);
- } else if (colorModeCount == 1) {
- mColorModeSpinner.setEnabled(false);
- mColorModeSpinner.setSelection(0);
} else {
mColorModeSpinner.setEnabled(true);
final int selectedColorModeIndex = Integer.numberOfTrailingZeros(
@@ -1262,9 +1310,6 @@ public class PrintJobConfigActivity extends Activity {
if (orientationCount <= 0) {
mOrientationSpinner.setEnabled(false);
mOrientationSpinner.setSelection(AdapterView.INVALID_POSITION);
- } else if (orientationCount == 1) {
- mOrientationSpinner.setEnabled(false);
- mOrientationSpinner.setSelection(0);
} else {
mOrientationSpinner.setEnabled(true);
final int selectedOrientationIndex = Integer.numberOfTrailingZeros(
@@ -1336,99 +1381,6 @@ public class PrintJobConfigActivity extends Activity {
}
}
- public void addPrinters(List<PrinterInfo> addedPrinters) {
- final int addedPrinterCount = addedPrinters.size();
- for (int i = 0; i < addedPrinterCount; i++) {
- PrinterInfo addedPrinter = addedPrinters.get(i);
- boolean duplicate = false;
- final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
- for (int j = 0; j < existingPrinterCount; j++) {
- PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
- if (addedPrinter.getId().equals(existingPrinter.getId())) {
- duplicate = true;
- break;
- }
- }
- if (!duplicate) {
- mDestinationSpinnerAdapter.add(new SpinnerItem<PrinterInfo>(
- addedPrinter, addedPrinter.getName()));
- } else {
- Log.w(LOG_TAG, "Skipping a duplicate printer: " + addedPrinter);
- }
- }
-
- if (mDestinationSpinner.getSelectedItemPosition() == AdapterView.INVALID_POSITION
- && mDestinationSpinnerAdapter.getCount() > 0) {
- mDestinationSpinner.setSelection(0);
- }
-
- mEditor.updateUi();
- }
-
- public void removePrinters(List<PrinterId> pritnerIds) {
- final int printerIdCount = pritnerIds.size();
- for (int i = 0; i < printerIdCount; i++) {
- PrinterId removedPrinterId = pritnerIds.get(i);
- boolean removed = false;
- final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
- for (int j = 0; j < existingPrinterCount; j++) {
- PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
- if (removedPrinterId.equals(existingPrinter.getId())) {
- mDestinationSpinnerAdapter.remove(mDestinationSpinnerAdapter.getItem(j));
- removed = true;
- break;
- }
- }
- if (!removed) {
- Log.w(LOG_TAG, "Ignoring not added printer with id: " + removedPrinterId);
- }
- }
-
- if (mDestinationSpinner.getSelectedItemPosition() != AdapterView.INVALID_POSITION
- && mDestinationSpinnerAdapter.getCount() == 0) {
- mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION);
- }
- }
-
- @SuppressWarnings("unchecked")
- public void updatePrinters(List<PrinterInfo> pritners) {
- SpinnerItem<PrinterInfo> selectedItem =
- (SpinnerItem<PrinterInfo>) mDestinationSpinner.getSelectedItem();
- PrinterId selectedPrinterId = (selectedItem != null)
- ? selectedItem.value.getId() : null;
-
- boolean updated = false;
-
- final int printerCount = pritners.size();
- for (int i = 0; i < printerCount; i++) {
- PrinterInfo updatedPrinter = pritners.get(i);
- final int existingPrinterCount = mDestinationSpinnerAdapter.getCount();
- for (int j = 0; j < existingPrinterCount; j++) {
- PrinterInfo existingPrinter = mDestinationSpinnerAdapter.getItem(j).value;
- if (updatedPrinter.getId().equals(existingPrinter.getId())) {
- existingPrinter.copyFrom(updatedPrinter);
- updated = true;
- if (selectedPrinterId != null
- && selectedPrinterId.equals(updatedPrinter.getId())) {
- // The selected printer was updated. We simulate a fake
- // selection to reuse the normal printer change handling.
- mOnItemSelectedListener.onItemSelected(mDestinationSpinner,
- mDestinationSpinner.getSelectedView(),
- mDestinationSpinner.getSelectedItemPosition(),
- mDestinationSpinner.getSelectedItemId());
- // TODO: This will reset the UI to the defaults for the
- // printer. We may need to revisit this.
-
- }
- break;
- }
- }
- }
- if (updated) {
- mDestinationSpinnerAdapter.notifyDataSetChanged();
- }
- }
-
private boolean hasErrors() {
return mRangeEditText.getError() != null
|| mCopiesEditText.getError() != null;
@@ -1455,10 +1407,39 @@ public class PrintJobConfigActivity extends Activity {
}
}
- private final class DestinationAdapter extends ArrayAdapter<SpinnerItem<PrinterInfo>> {
+ private final class DestinationAdapter extends BaseAdapter {
+ private final AvailablePrinterProvider mProvider;
- public DestinationAdapter() {
- super( PrintJobConfigActivity.this, R.layout.spinner_dropdown_item);
+ private final DataSetObserver mObserver = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ notifyDataSetInvalidated();
+ }
+ };
+
+ public DestinationAdapter(AvailablePrinterProvider provider) {
+ mProvider = provider;
+ mProvider.registerObserver(mObserver);
+ }
+
+ @Override
+ public int getCount() {
+ return mProvider.getItemCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mProvider.getItemAt(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
}
@Override
@@ -1474,7 +1455,7 @@ public class PrintJobConfigActivity extends Activity {
R.layout.spinner_dropdown_item, parent, false);
}
- PrinterInfo printerInfo = getItem(position).value;
+ PrinterInfo printerInfo = mProvider.getItemAt(position);
TextView title = (TextView) convertView.findViewById(R.id.title);
title.setText(printerInfo.getName());
@@ -1495,132 +1476,6 @@ public class PrintJobConfigActivity extends Activity {
}
}
- private static final class PrinterDiscoverySessionObserver
- extends IPrinterDiscoverySessionObserver.Stub {
- private static final int MSG_SET_CONTROLLER = 1;
- private static final int MSG_ON_PRINTERS_ADDED = 2;
- private static final int MSG_ON_PRINTERS_REMOVED = 3;
- private static final int MSG_ON_PRINTERS_UPDATED = 4;
-
- private Handler mHandler;
- private Editor mEditor;
- private IPrinterDiscoverySessionController mController;
-
- @SuppressWarnings("unchecked")
- public PrinterDiscoverySessionObserver(Editor editor, Looper looper) {
- mEditor = editor;
- mHandler = new Handler(looper, null, true) {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_SET_CONTROLLER: {
- mController = (IPrinterDiscoverySessionController) message.obj;
- // TODO: This should be cleaned up
- List<PrinterId> printerIds = Collections.emptyList();
- try {
- mController.open(printerIds);
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error starting printer discovery");
- }
- } break;
-
- case MSG_ON_PRINTERS_ADDED: {
- List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
- mEditor.addPrinters(printers);
- } break;
-
- case MSG_ON_PRINTERS_REMOVED: {
- List<PrinterId> printerIds = (List<PrinterId>) message.obj;
- mEditor.removePrinters(printerIds);
- } break;
-
- case MSG_ON_PRINTERS_UPDATED: {
- List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
- mEditor.updatePrinters(printers);
- } break;
- }
- }
- };
- }
-
- public void open(List<PrinterId> priorityList) {
- if (mController != null) {
- try {
- mController.open(priorityList);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error closing printer discovery session", re);
- }
- }
- }
-
- public void close() {
- if (mController != null) {
- try {
- mController.close();
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error closing printer discovery session", re);
- }
- }
- }
-
- public void requestPrinterUpdate(PrinterId printerId) {
- if (mController != null) {
- try {
- mController.requestPrinterUpdate(printerId);
- } catch (RemoteException re) {
- Log.e(LOG_TAG, "Error requestin printer update", re);
- }
- }
- }
-
- @Override
- public void setController(IPrinterDiscoverySessionController controller) {
- synchronized (this) {
- if (mHandler != null) {
- mHandler.obtainMessage(MSG_SET_CONTROLLER, controller)
- .sendToTarget();
- }
- }
- }
-
- @Override
- public void onPrintersAdded(List<PrinterInfo> printers) {
- synchronized (this) {
- if (mHandler != null) {
- mHandler.obtainMessage(MSG_ON_PRINTERS_ADDED, printers)
- .sendToTarget();
- }
- }
- }
-
- @Override
- public void onPrintersRemoved(List<PrinterId> printers) {
- synchronized (this) {
- if (mHandler != null) {
- mHandler.obtainMessage(MSG_ON_PRINTERS_REMOVED, printers)
- .sendToTarget();
- }
- }
- }
-
- @Override
- public void onPrintersUpdated(List<PrinterInfo> printers) {
- synchronized (this) {
- if (mHandler != null) {
- mHandler.obtainMessage(MSG_ON_PRINTERS_UPDATED, printers)
- .sendToTarget();
- }
- }
- }
-
- public void destroy() {
- synchronized (this) {
- mHandler = null;
- mEditor = null;
- }
- }
- }
-
/**
* An instance of this class class is intended to be the first focusable
* in a layout to which the system automatically gives focus. It performs
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
index 1b8b81a..c2cf65e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpooler.java
@@ -477,7 +477,7 @@ public class PrintSpooler {
private static final String ATTR_FITTING_MODE = "fittingMode";
private static final String ATTR_ORIENTATION = "orientation";
- private static final String ATTR_PRINTER_NAME = "printerName";
+ private static final String ATTR_LOCAL_ID = "printerName";
private static final String ATTR_SERVICE_NAME = "serviceName";
private static final String ATTR_WIDTH_MILS = "widthMils";
@@ -568,7 +568,7 @@ public class PrintSpooler {
PrinterId printerId = printJob.getPrinterId();
if (printerId != null) {
serializer.startTag(null, TAG_PRINTER_ID);
- serializer.attribute(null, ATTR_PRINTER_NAME, printerId.getLocalId());
+ serializer.attribute(null, ATTR_LOCAL_ID, printerId.getLocalId());
serializer.attribute(null, ATTR_SERVICE_NAME, printerId.getServiceName()
.flattenToString());
serializer.endTag(null, TAG_PRINTER_ID);
@@ -695,13 +695,7 @@ public class PrintSpooler {
Slog.w(LOG_TAG, "Failed to write state, restoring backup.", e);
mStatePersistFile.failWrite(out);
} finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException ioe) {
- /* ignore */
- }
- }
+ IoUtils.closeQuietly(out);
}
}
@@ -733,11 +727,7 @@ public class PrintSpooler {
} catch (IndexOutOfBoundsException iobe) {
Slog.w(LOG_TAG, "Failed parsing ", iobe);
} finally {
- try {
- in.close();
- } catch (IOException ioe) {
- /* ignore */
- }
+ IoUtils.closeQuietly(in);
}
}
@@ -784,7 +774,7 @@ public class PrintSpooler {
skipEmptyTextTags(parser);
if (accept(parser, XmlPullParser.START_TAG, TAG_PRINTER_ID)) {
- String localId = parser.getAttributeValue(null, ATTR_PRINTER_NAME);
+ String localId = parser.getAttributeValue(null, ATTR_LOCAL_ID);
ComponentName service = ComponentName.unflattenFromString(parser.getAttributeValue(
null, ATTR_SERVICE_NAME));
printJob.setPrinterId(new PrinterId(service, localId));
diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java
index 322de6c..491dddc 100644
--- a/services/java/com/android/server/print/RemotePrintService.java
+++ b/services/java/com/android/server/print/RemotePrintService.java
@@ -110,6 +110,7 @@ final class RemotePrintService implements DeathRecipient {
}
private void handleBinderDied() {
+ mPendingCommands.clear();
ensureUnbound();
}