diff options
author | Svetoslav <svetoslavganov@google.com> | 2013-08-14 07:09:25 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2013-08-14 07:09:25 +0000 |
commit | 59703c7186ea49669e7dd326a1e2e704385cbaff (patch) | |
tree | 9e83f12db6224b33db3799e459ce10444645a003 | |
parent | 3dfa5eb9d9eeb12d761194cb06dc1ba63ed61e95 (diff) | |
parent | 66160bb881470a691005c8ad4e9c31c41fd5f810 (diff) | |
download | frameworks_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
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(); } |