From 66160bb881470a691005c8ad4e9c31c41fd5f810 Mon Sep 17 00:00:00 2001 From: Svetoslav Date: Mon, 12 Aug 2013 22:36:50 -0700 Subject: [PATCH] Partial implementation for the favorite and available printer tracking. 1. Added a dedicated class that keeps track of the user's favorite printers based on past usage. We keep the last 50 uses and assign a decreasing weight to older historical use records. The printer whose records' sum is the largest is considered the favorite for the user and so on. 2. Factored out the printer discovery logic from the print job config activity into a separate available printers provider class. It encapsulates all the logic to communicated with the remote print services to discover printers, keep track of added, updated, and removed printers. 3. Preliminary scetch of the printer chooser acitivty that will show all the printers. Change-Id: I5524665f2a9a565f186db85214d5e41a44f4812e --- packages/PrintSpooler/AndroidManifest.xml | 6 + .../res/layout/choose_printer_activity.xml | 23 + .../res/menu/choose_printer_activity.xml | 29 ++ packages/PrintSpooler/res/values/strings.xml | 5 + .../AvailablePrinterProvider.java | 285 ++++++++++++ .../printspooler/ChoosePrinterActivity.java | 28 ++ .../com/android/printspooler/DataLoader.java | 33 ++ .../android/printspooler/DataProvider.java | 50 +++ .../printspooler/FavoritePrinterProvider.java | 364 ++++++++++++++++ .../printspooler/PrintJobConfigActivity.java | 405 ++++++------------ .../android/printspooler/PrintSpooler.java | 20 +- .../server/print/RemotePrintService.java | 1 + 12 files changed, 959 insertions(+), 290 deletions(-) create mode 100644 packages/PrintSpooler/res/layout/choose_printer_activity.xml create mode 100644 packages/PrintSpooler/res/menu/choose_printer_activity.xml create mode 100644 packages/PrintSpooler/src/com/android/printspooler/AvailablePrinterProvider.java create mode 100644 packages/PrintSpooler/src/com/android/printspooler/ChoosePrinterActivity.java create mode 100644 packages/PrintSpooler/src/com/android/printspooler/DataLoader.java create mode 100644 packages/PrintSpooler/src/com/android/printspooler/DataProvider.java create mode 100644 packages/PrintSpooler/src/com/android/printspooler/FavoritePrinterProvider.java diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index 74fd7a85d8a03..c00639d57cdf8 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -50,6 +50,12 @@ android:theme="@style/PrintJobConfigActivityTheme"> + + + 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 0000000000000..c34a108f5024b --- /dev/null +++ b/packages/PrintSpooler/res/layout/choose_printer_activity.xml @@ -0,0 +1,23 @@ + + + + + + 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 0000000000000..3774279518ee3 --- /dev/null +++ b/packages/PrintSpooler/res/menu/choose_printer_activity.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 2086f58f6c2d7..1cd611f0c9202 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -58,6 +58,11 @@ Generating print job + + + + Search + 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 0000000000000..658a22417418f --- /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 + implements DataLoader { + private static final String LOG_TAG = "AvailablePrinterProvider"; + + private final Set mPrinteIdsSet = new ArraySet(); + + private final List mPrinters = new ArrayList(); + + private final List mPriorityList; + + private PrinterDiscoverySession mDiscoverySession; + + public AvailablePrinterProvider(Context context, List 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 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 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 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 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 printers = (List) message.obj; + addPrinters(printers); + } break; + + case MSG_ON_PRINTERS_REMOVED: { + List printers = (List) message.obj; + removePrinters(printers); + } break; + + case MSG_ON_PRINTERS_UPDATED: { + List printers = (List) message.obj; + updatePrinters(printers); + } break; + }; + } + } + } + + private static final class PrinterDiscoverySessionObserver + extends IPrinterDiscoverySessionObserver.Stub { + + private final WeakReference mWeakSession; + + public PrinterDiscoverySessionObserver(PrinterDiscoverySession session) { + mWeakSession = new WeakReference(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 printers) { + PrinterDiscoverySession sesison = mWeakSession.get(); + if (sesison != null) { + sesison.mHandler.obtainMessage( + PrinterDiscoverySession.SessionHandler.MSG_ON_PRINTERS_ADDED, + printers).sendToTarget(); + } + } + + @Override + public void onPrintersRemoved(List printers) { + PrinterDiscoverySession session = mWeakSession.get(); + if (session != null) { + session.mHandler.obtainMessage( + PrinterDiscoverySession.SessionHandler.MSG_ON_PRINTERS_REMOVED, + printers).sendToTarget(); + } + } + + @Override + public void onPrintersUpdated(List 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 0000000000000..8b0dd66a9739d --- /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 0000000000000..82cc2e10d5f2b --- /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 0000000000000..7b10903f55701 --- /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 The type of the providers data. + */ +public abstract class DataProvider 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 0000000000000..2c539d192611d --- /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 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 mHistoricalPrinters = new ArrayList(); + + private final List mFavoritePrinters = new ArrayList(); + + 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 recordMap = + new ArrayMap(); + + // 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 { + 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, Void, Void>() { + @Override + protected Void doInBackground(List... printers) { + doWriteState(printers[0]); + return null; + } + + @Override + protected void onPostExecute(Void result) { + notifyChanged(); + } + + }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, + new ArrayList(mHistoricalPrinters)); + } + + private void doWriteState(List 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 9160b7d1ffe86..f8e9f43eda3f1 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> mDestinationSpinnerAdapter; + private final DestinationAdapter mDestinationSpinnerAdapter; private final Spinner mMediaSizeSpinner; private final ArrayAdapter> mMediaSizeSpinnerAdapter; @@ -623,15 +645,18 @@ public class PrintJobConfigActivity extends Activity { return; } mCurrPrintAttributes.clear(); - SpinnerItem 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 printerIds = new ArrayList(); 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 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( - 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 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 pritners) { - SpinnerItem selectedItem = - (SpinnerItem) 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> { + 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 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 printers = (List) message.obj; - mEditor.addPrinters(printers); - } break; - - case MSG_ON_PRINTERS_REMOVED: { - List printerIds = (List) message.obj; - mEditor.removePrinters(printerIds); - } break; - - case MSG_ON_PRINTERS_UPDATED: { - List printers = (List) message.obj; - mEditor.updatePrinters(printers); - } break; - } - } - }; - } - - public void open(List 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 printers) { - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(MSG_ON_PRINTERS_ADDED, printers) - .sendToTarget(); - } - } - } - - @Override - public void onPrintersRemoved(List printers) { - synchronized (this) { - if (mHandler != null) { - mHandler.obtainMessage(MSG_ON_PRINTERS_REMOVED, printers) - .sendToTarget(); - } - } - } - - @Override - public void onPrintersUpdated(List 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 1b8b81a21fa68..c2cf65ee7ffab 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 322de6cae3aa8..491dddcaa9b05 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(); }