am 59703c71: Merge "Partial implementation for the favorite and available printer tracking." into klp-dev
* commit '59703c7186ea49669e7dd326a1e2e704385cbaff': Partial implementation for the favorite and available printer tracking.
This commit is contained in:
@@ -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" >
|
||||
|
||||
23
packages/PrintSpooler/res/layout/choose_printer_activity.xml
Normal file
23
packages/PrintSpooler/res/layout/choose_printer_activity.xml
Normal file
@@ -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>
|
||||
|
||||
29
packages/PrintSpooler/res/menu/choose_printer_activity.xml
Normal file
29
packages/PrintSpooler/res/menu/choose_printer_activity.xml
Normal file
@@ -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>
|
||||
@@ -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] -->
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -110,6 +110,7 @@ final class RemotePrintService implements DeathRecipient {
|
||||
}
|
||||
|
||||
private void handleBinderDied() {
|
||||
mPendingCommands.clear();
|
||||
ensureUnbound();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user