Merge "Print UI bug fixing and printer discovery refactoring." into klp-dev

This commit is contained in:
Svetoslav Ganov
2013-08-23 20:00:29 +00:00
committed by Android (Google) Code Review
20 changed files with 1626 additions and 855 deletions

View File

@@ -162,6 +162,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IVibratorService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
core/java/android/print/IPrintDocumentAdapter.aidl \
core/java/android/print/IPrintClient.aidl \
core/java/android/print/IPrintManager.aidl \

View File

@@ -18,8 +18,6 @@ package android.os;
import android.util.ArrayMap;
import java.util.HashMap;
/**
* Takes care of the grunt work of maintaining a list of remote interfaces,
* typically for the use of performing callbacks from a

View File

@@ -16,8 +16,10 @@
package android.print;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
@@ -34,4 +36,12 @@ interface IPrintManager {
int appId, int userId);
void cancelPrintJob(int printJobId, int appId, int userId);
void restartPrintJob(int printJobId, int appId, int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
in List<PrinterId> priorityList, int userId);
void stopPrinterDiscovery(in IPrinterDiscoveryObserver observer, int userId);
void requestPrinterUpdate(in PrinterId printerId, int userId);
void destroyPrinterDiscoverySession(in IPrinterDiscoveryObserver observer,
int userId);
}

View File

@@ -18,7 +18,6 @@ package android.print;
import android.content.ComponentName;
import android.os.ParcelFileDescriptor;
import android.print.PrinterId;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
import android.print.IPrintSpoolerClient;
@@ -47,9 +46,4 @@ oneway interface IPrintSpooler {
int sequence);
void writePrintJobData(in ParcelFileDescriptor fd, int printJobId);
void setClient(IPrintSpoolerClient client);
// Printer discovery APIs
void onPrintersAdded(in List<PrinterInfo> printers);
void onPrintersRemoved(in List<PrinterId> printerIds);
void onPrintersUpdated(in List<PrinterInfo> printerIds);
}

View File

@@ -17,7 +17,6 @@
package android.print;
import android.content.ComponentName;
import android.print.PrinterId;
import android.print.PrintJobInfo;
@@ -30,11 +29,4 @@ oneway interface IPrintSpoolerClient {
void onPrintJobQueued(in PrintJobInfo printJob);
void onAllPrintJobsForServiceHandled(in ComponentName printService);
void onAllPrintJobsHandled();
// Printer discovery APIs
void createPrinterDiscoverySession();
void startPrinterDiscovery(in List<PrinterId> priorityList);
void stopPrinterDiscovery();
void requestPrinterUpdate(in PrinterId printerId);
void destroyPrinterDiscoverySession();
}

View File

@@ -0,0 +1,32 @@
/*
* 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 android.print;
import android.print.IPrintClient;
import android.print.PrinterId;
import android.print.PrinterInfo;
/**
* Interface for observing discovered printers by a discovery session.
*
* @hide
*/
oneway interface IPrinterDiscoveryObserver {
void onPrintersAdded(in List<PrinterInfo> printers);
void onPrintersRemoved(in List<PrinterId> printerIds);
void onPrintersUpdated(in List<PrinterInfo> printerIds);
}

View File

@@ -204,6 +204,13 @@ public final class PrintManager {
return null;
}
/**
* @hide
*/
public PrinterDiscoverySession createPrinterDiscoverySession() {
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
private static final class PrintClient extends IPrintClient.Stub {
private final WeakReference<PrintManager> mWeakPrintManager;

View File

@@ -0,0 +1,297 @@
/*
* 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 android.print;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @hide
*/
public final class PrinterDiscoverySession {
private static final String LOG_TAG ="PrinterDiscoverySession";
private static final int MSG_PRINTERS_ADDED = 1;
private static final int MSG_PRINTERS_REMOVED = 2;
private static final int MSG_PRINTERS_UPDATED = 3;
private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
new ArrayMap<PrinterId, PrinterInfo>();
private final IPrintManager mPrintManager;
private final int mUserId;
private final Handler mHandler;
private IPrinterDiscoveryObserver mObserver;
private OnPrintersChangeListener mListener;
private boolean mIsPrinterDiscoveryStarted;
public static interface OnPrintersChangeListener {
public void onPrintersChanged();
}
PrinterDiscoverySession(IPrintManager printManager, Context context, int userId) {
mPrintManager = printManager;
mUserId = userId;
mHandler = new SessionHandler(context.getMainLooper());
mObserver = new PrinterDiscoveryObserver(this);
try {
mPrintManager.createPrinterDiscoverySession(mObserver, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error creating printer discovery session", re);
}
}
public final void startPrinterDisovery(List<PrinterId> priorityList) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring start printers dsicovery - session destroyed");
}
if (!mIsPrinterDiscoveryStarted) {
mIsPrinterDiscoveryStarted = true;
try {
mPrintManager.startPrinterDiscovery(mObserver, priorityList, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error starting printer discovery", re);
}
}
}
public final void stopPrinterDiscovery() {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring stop printers discovery - session destroyed");
}
if (mIsPrinterDiscoveryStarted) {
mIsPrinterDiscoveryStarted = false;
try {
mPrintManager.stopPrinterDiscovery(mObserver, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error stopping printer discovery", re);
}
}
}
public final void requestPrinterUpdate(PrinterId printerId) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring reqeust printer update - session destroyed");
}
try {
mPrintManager.requestPrinterUpdate(printerId, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error requesting printer update", re);
}
}
public final void destroy() {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring destroy - session destroyed");
}
destroyNoCheck();
}
public final List<PrinterInfo> getPrinters() {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring get printers - session destroyed");
return Collections.emptyList();
}
return new ArrayList<PrinterInfo>(mPrinters.values());
}
public final boolean isDestroyed() {
throwIfNotCalledOnMainThread();
return isDestroyedNoCheck();
}
public final boolean isPrinterDiscoveryStarted() {
throwIfNotCalledOnMainThread();
return mIsPrinterDiscoveryStarted;
}
public final void setOnPrintersChangeListener(OnPrintersChangeListener listener) {
throwIfNotCalledOnMainThread();
mListener = listener;
}
@Override
protected final void finalize() throws Throwable {
if (!isDestroyedNoCheck()) {
Log.e(LOG_TAG, "Destroying leaked printer discovery session");
destroyNoCheck();
}
super.finalize();
}
private boolean isDestroyedNoCheck() {
return (mObserver == null);
}
private void destroyNoCheck() {
stopPrinterDiscovery();
try {
mPrintManager.destroyPrinterDiscoverySession(mObserver, mUserId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error destroying printer discovery session", re);
} finally {
mObserver = null;
mPrinters.clear();
}
}
private void handlePrintersAdded(List<PrinterInfo> printers) {
if (isDestroyed()) {
return;
}
boolean printersChanged = false;
final int addedPrinterCount = printers.size();
for (int i = 0; i < addedPrinterCount; i++) {
PrinterInfo addedPrinter = printers.get(i);
if (mPrinters.get(addedPrinter.getId()) == null) {
mPrinters.put(addedPrinter.getId(), addedPrinter);
printersChanged = true;
}
}
if (printersChanged) {
notifyOnPrintersChanged();
}
}
private void handlePrintersRemoved(List<PrinterId> printerIds) {
if (isDestroyed()) {
return;
}
boolean printersChanged = false;
final int removedPrinterIdCount = printerIds.size();
for (int i = 0; i < removedPrinterIdCount; i++) {
PrinterId removedPrinterId = printerIds.get(i);
if (mPrinters.remove(removedPrinterId) != null) {
printersChanged = true;
}
}
if (printersChanged) {
notifyOnPrintersChanged();
}
}
private void handlePrintersUpdated(List<PrinterInfo> printers) {
if (isDestroyed()) {
return;
}
boolean printersChanged = false;
final int updatedPrinterCount = printers.size();
for (int i = 0; i < updatedPrinterCount; i++) {
PrinterInfo updatedPrinter = printers.get(i);
PrinterInfo oldPrinter = mPrinters.get(updatedPrinter.getId());
if (oldPrinter != null && !oldPrinter.equals(updatedPrinter)) {
mPrinters.put(updatedPrinter.getId(), updatedPrinter);
printersChanged = true;
}
}
if (printersChanged) {
notifyOnPrintersChanged();
}
}
private void notifyOnPrintersChanged() {
if (mListener != null) {
mListener.onPrintersChanged();
}
}
private static void throwIfNotCalledOnMainThread() {
if (!Looper.getMainLooper().isCurrentThread()) {
throw new IllegalAccessError("must be called from the main thread");
}
}
private final class SessionHandler extends Handler {
public SessionHandler(Looper looper) {
super(looper, null, false);
}
@Override
@SuppressWarnings("unchecked")
public void handleMessage(Message message) {
switch (message.what) {
case MSG_PRINTERS_ADDED: {
List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
handlePrintersAdded(printers);
} break;
case MSG_PRINTERS_REMOVED: {
List<PrinterId> printerIds = (List<PrinterId>) message.obj;
handlePrintersRemoved(printerIds);
} break;
case MSG_PRINTERS_UPDATED: {
List<PrinterInfo> printers = (List<PrinterInfo>) message.obj;
handlePrintersUpdated(printers);
} break;
}
}
}
private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
private final WeakReference<PrinterDiscoverySession> mWeakSession;
public PrinterDiscoveryObserver(PrinterDiscoverySession session) {
mWeakSession = new WeakReference<PrinterDiscoverySession>(session);
}
@Override
public void onPrintersAdded(List<PrinterInfo> printers) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_ADDED,
printers).sendToTarget();
}
}
@Override
public void onPrintersRemoved(List<PrinterId> printerIds) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_REMOVED,
printerIds).sendToTarget();
}
}
@Override
public void onPrintersUpdated(List<PrinterInfo> printers) {
PrinterDiscoverySession session = mWeakSession.get();
if (session != null) {
session.mHandler.obtainMessage(MSG_PRINTERS_UPDATED,
printers).sendToTarget();
}
}
}
}

View File

@@ -18,12 +18,12 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.printspooler"
android:sharedUserId="android.uid.system"
android:sharedUserId="android.uid.printspooler"
android:versionName="1"
android:versionCode="1"
coreApp="true">
<uses-sdk android:minSdkVersion="17" android:targetSdkVersion="17"/>
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/>
<uses-permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
@@ -36,7 +36,8 @@
<application
android:allowClearUserData="false"
android:label="@string/app_label"
android:allowBackup= "false">
android:allowBackup= "false"
android:supportsRtl="true">
<service
android:name=".PrintSpoolerService"
@@ -46,6 +47,7 @@
<activity
android:name=".PrintJobConfigActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:theme="@style/PrintJobConfigActivityTheme">
</activity>

View File

@@ -14,208 +14,234 @@
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/content_editing"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
android:orientation="vertical"
android:scrollbars="vertical"
android:background="@color/editable_background">
<ScrollView
<GridLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:scrollbars="vertical"
android:background="@color/editable_background">
android:columnCount="2">
<GridLayout
android:layout_width="wrap_content"
<!-- Destination -->
<Spinner
android:id="@+id/destination_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:layout_marginTop="24dip"
android:layout_marginStart="24dip"
android:layout_marginEnd="24dip"
android:layout_row="0"
android:layout_column="0"
android:layout_columnSpan="2"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
</Spinner>
<!-- Copies -->
<view
class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
android:id="@+id/copies_edittext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dip"
android:layout_marginTop="32dip"
android:layout_marginEnd="6dip"
android:layout_row="2"
android:layout_column="0"
android:layout_gravity="bottom|fill_horizontal"
style="@style/PrintOptionEditTextStyle"
android:inputType="numberDecimal">
</view>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="36dip"
android:layout_marginEnd="6dip"
android:layout_row="1"
android:layout_column="0"
android:layout_gravity="start|bottom"
style="@style/PrintOptionTextViewStyle"
android:labelFor="@id/copies_edittext"
android:text="@string/label_copies">
</TextView>
<!-- Paper size -->
<Spinner
android:id="@+id/paper_size_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dip"
android:layout_marginEnd="24dip"
android:layout_marginBottom="24dip"
android:orientation="vertical"
android:columnCount="2">
android:layout_row="2"
android:layout_column="1"
android:layout_gravity="fill_horizontal"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<!-- Destination -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="18dip"
android:layout_marginEnd="24dip"
android:layout_row="1"
android:layout_column="1"
style="@style/PrintOptionTextViewStyle"
android:labelFor="@id/paper_size_spinner"
android:text="@string/label_paper_size">
</TextView>
<Spinner
android:id="@+id/destination_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:layout_row="0"
android:layout_column="0"
android:layout_columnSpan="2"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
</Spinner>
<!-- Color -->
<!-- Copies -->
<Spinner
android:id="@+id/color_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dip"
android:layout_marginEnd="6dip"
android:layout_row="4"
android:layout_column="0"
android:layout_gravity="fill_horizontal"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<view
class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
android:id="@+id/copies_edittext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="6dip"
android:layout_row="2"
android:layout_column="0"
android:layout_gravity="bottom"
android:inputType="numberDecimal"
android:selectAllOnFocus="true"
android:minWidth="150dip"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
</view>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="36dip"
android:layout_marginEnd="6dip"
android:layout_row="3"
android:layout_column="0"
style="@style/PrintOptionTextViewStyle"
android:labelFor="@id/color_spinner"
android:text="@string/label_color">
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="12dip"
android:layout_marginEnd="6dip"
android:layout_row="1"
android:layout_column="0"
android:layout_gravity="start|bottom"
android:labelFor="@id/copies_edittext"
android:text="@string/label_copies"
android:textAppearance="@style/PrintOptionTitleTextAppearance">
</TextView>
<!-- Orientation -->
<!-- Paper size -->
<Spinner
android:id="@+id/orientation_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dip"
android:layout_marginEnd="24dip"
android:layout_row="4"
android:layout_column="1"
android:layout_gravity="fill_horizontal"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<Spinner
android:id="@+id/paper_size_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dip"
android:layout_row="2"
android:layout_column="1"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="18dip"
android:layout_marginEnd="24dip"
android:layout_row="3"
android:layout_column="1"
style="@style/PrintOptionTextViewStyle"
android:labelFor="@id/orientation_spinner"
android:text="@string/label_orientation">
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="18dip"
android:layout_row="1"
android:layout_column="1"
android:labelFor="@id/paper_size_spinner"
android:text="@string/label_paper_size"
android:textAppearance="@style/PrintOptionTitleTextAppearance">
</TextView>
<!-- Range options -->
<!-- Color -->
<Spinner
android:id="@+id/range_options_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dip"
android:layout_marginEnd="6dip"
android:layout_row="6"
android:layout_column="0"
android:layout_gravity="fill_horizontal"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<Spinner
android:id="@+id/color_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="6dip"
android:layout_row="4"
android:layout_column="0"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<TextView
android:id="@+id/range_options_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="36dip"
android:layout_row="5"
android:layout_column="0"
style="@style/PrintOptionTextViewStyle"
android:labelFor="@id/range_options_spinner"
android:text="@string/label_pages">
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="12dip"
android:layout_marginEnd="6dip"
android:layout_row="3"
android:layout_column="0"
android:labelFor="@id/color_spinner"
android:text="@string/label_color"
android:textAppearance="@style/PrintOptionTitleTextAppearance">
</TextView>
<!-- Pages -->
<!-- Orientation -->
<view
class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
android:id="@+id/page_range_edittext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dip"
android:layout_marginEnd="24dip"
android:layout_row="6"
android:layout_column="1"
android:layout_gravity="bottom|fill_horizontal"
style="@style/PrintOptionEditTextStyle"
android:visibility="gone"
android:inputType="textNoSuggestions">
</view>
<Spinner
android:id="@+id/orientation_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dip"
android:layout_row="4"
android:layout_column="1"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<TextView
android:id="@+id/page_range_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="12dip"
android:layout_marginEnd="24dip"
android:layout_row="5"
android:layout_column="1"
style="@style/PrintOptionTextViewStyle"
android:labelFor="@id/page_range_edittext"
android:text="@string/pages_range_example"
android:textAllCaps="false">
</TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="18dip"
android:layout_row="3"
android:layout_column="1"
android:labelFor="@id/orientation_spinner"
android:text="@string/label_orientation"
android:textAppearance="@style/PrintOptionTitleTextAppearance">
</TextView>
<!-- Print button -->
<!-- Pages -->
<ImageView
android:layout_width="wrap_content"
android:layout_height="1dip"
android:layout_marginTop="24dip"
android:layout_row="7"
android:layout_column="0"
android:layout_columnSpan="2"
android:layout_gravity="fill_horizontal"
android:background="@color/separator"
android:contentDescription="@null">
</ImageView>
<Spinner
android:id="@+id/range_options_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="6dip"
android:layout_row="6"
android:layout_column="0"
style="@style/PrintOptionSpinnerStyle">
</Spinner>
<Button
android:id="@+id/print_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:layout_row="8"
android:layout_column="0"
android:layout_columnSpan="2"
android:text="@string/print_button"
android:textSize="16sp"
android:textColor="@color/important_text">
</Button>
<view
class="com.android.printspooler.PrintJobConfigActivity$CustomEditText"
android:id="@+id/page_range_edittext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="6dip"
android:layout_row="6"
android:layout_column="1"
android:layout_gravity="bottom"
android:selectAllOnFocus="true"
android:minWidth="150dip"
android:hint="@string/pages_range_example"
android:inputType="textNoSuggestions"
android:visibility="gone"
android:minHeight="?android:attr/listPreferredItemHeightSmall">
</view>
</GridLayout>
<TextView
android:id="@+id/page_range_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dip"
android:layout_marginStart="12dip"
android:layout_row="5"
android:layout_column="0"
android:labelFor="@id/range_options_spinner"
android:text="@string/label_pages"
android:textAppearance="@style/PrintOptionTitleTextAppearance">
</TextView>
</ScrollView>
</GridLayout>
</ScrollView>
<View
android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="@color/separator">
</View>
<Button
android:id="@+id/print_button"
style="?android:attr/buttonBarButtonStyle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="fill_horizontal"
android:text="@string/print_button"
android:textSize="16sp"
android:textColor="@color/important_text">
</Button>
</LinearLayout>

View File

@@ -22,6 +22,9 @@
<!-- Label of the print dialog's print button. [CHAR LIMIT=16] -->
<string name="print_button">Print</string>
<!-- Label of the print dialog's save button. [CHAR LIMIT=16] -->
<string name="save_button">Save</string>
<!-- Label of the destination widget. [CHAR LIMIT=20] -->
<string name="label_destination">DESTIINATION</string>
@@ -41,7 +44,7 @@
<string name="label_pages">PAGES (<xliff:g id="page_count" example="5">%1$s</xliff:g>)</string>
<!-- Page range exmple used as a hint of how to specify such. [CHAR LIMIT=15] -->
<string name="pages_range_example">e.g. 1&#8211;5, 8</string>
<string name="pages_range_example">e.g. 1&#8211;5, 8, 11&#8211;13</string>
<!-- Title for the pring preview button .[CHAR LIMIT=30] -->
<string name="print_preview">Print preview</string>
@@ -62,11 +65,7 @@
<string name="save_as_pdf">Save as PDF</string>
<!-- Title for the open all printers UI option in the printer list. [CHAR LIMIT=30] -->
<string name="all_printers">All printers\.\.\.</string>
<!-- Title for the searching for printers option in the printer list
(only option if not printers are available). [CHAR LIMIT=40] -->
<string name="searching_for_printers">Searching for printers\.\.\.</string>
<string name="all_printers">All printers&#8230;</string>
<!-- Select printer activity -->

View File

@@ -27,7 +27,21 @@
<item name="android:paddingTop">0dip</item>
<item name="android:paddingBottom">0dip</item>
<item name="android:minWidth">150dip</item>
<item name="android:maxWidth">200dip</item>
<item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
</style>
<style name="PrintOptionEditTextStyle">
<item name="android:selectAllOnFocus">true</item>
<item name="android:minHeight">?android:attr/listPreferredItemHeightSmall</item>
<item name="android:maxWidth">200dip</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
</style>
<style name="PrintOptionTextViewStyle">
<item name="android:textAppearance">@style/PrintOptionTitleTextAppearance</item>
<item name="android:maxWidth">200dip</item>
</style>
</resources>

View File

@@ -18,7 +18,7 @@
<style name="PrintJobConfigActivityTheme" parent="@android:style/Theme.Holo.Light.NoActionBar">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden|adjustPan</item>
<item name="android:windowSoftInputMode">stateAlwaysHidden|adjustResize</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:colorBackgroundCacheHint">@android:color/transparent</item>

View File

@@ -21,6 +21,9 @@ import android.content.Context;
import android.content.Loader;
import android.os.AsyncTask;
import android.os.Build;
import android.print.PrintManager;
import android.print.PrinterDiscoverySession;
import android.print.PrinterDiscoverySession.OnPrintersChangeListener;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.util.ArrayMap;
@@ -30,7 +33,6 @@ import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import com.android.printspooler.PrintSpoolerService.PrinterDiscoverySession;
import libcore.io.IoUtils;
@@ -62,7 +64,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private static final int MAX_HISTORY_LENGTH = 50;
private static final int MAX_HISTORICAL_PRINTER_COUNT = 4;
private static final int MAX_FAVORITE_PRINTER_COUNT = 4;
private final Map<PrinterId, PrinterInfo> mPrinters =
new LinkedHashMap<PrinterId, PrinterInfo>();
@@ -96,7 +98,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected void onStartLoading() {
if (DEBUG) {
Log.i(LOG_TAG, "onStartLoading()");
Log.i(LOG_TAG, "onStartLoading()" + FusedPrintersProvider.this.hashCode());
}
// The contract is that if we already have a valid,
// result the we have to deliver it immediately.
@@ -113,7 +115,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected void onStopLoading() {
if (DEBUG) {
Log.i(LOG_TAG, "onStopLoading()");
Log.i(LOG_TAG, "onStopLoading()" + FusedPrintersProvider.this.hashCode());
}
onCancelLoad();
}
@@ -121,7 +123,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected void onForceLoad() {
if (DEBUG) {
Log.i(LOG_TAG, "onForceLoad()");
Log.i(LOG_TAG, "onForceLoad()" + FusedPrintersProvider.this.hashCode());
}
onCancelLoad();
loadInternal();
@@ -129,12 +131,21 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
private void loadInternal() {
if (mDiscoverySession == null) {
mDiscoverySession = new MyPrinterDiscoverySession();
PrintManager printManager = (PrintManager) getContext()
.getSystemService(Context.PRINT_SERVICE);
mDiscoverySession = printManager.createPrinterDiscoverySession();
mDiscoverySession.setOnPrintersChangeListener(new OnPrintersChangeListener() {
@Override
public void onPrintersChanged() {
deliverResult(new ArrayList<PrinterInfo>(
mDiscoverySession.getPrinters()));
}
});
mPersistenceManager.readPrinterHistory();
}
if (mPersistenceManager.isReadHistoryCompleted()
&& !mDiscoverySession.isStarted()) {
final int favoriteCount = Math.min(MAX_HISTORICAL_PRINTER_COUNT,
&& !mDiscoverySession.isPrinterDiscoveryStarted()) {
final int favoriteCount = Math.min(MAX_FAVORITE_PRINTER_COUNT,
mFavoritePrinters.size());
List<PrinterId> printerIds = new ArrayList<PrinterId>(favoriteCount);
for (int i = 0; i < favoriteCount; i++) {
@@ -147,13 +158,14 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected boolean onCancelLoad() {
if (DEBUG) {
Log.i(LOG_TAG, "onCancelLoad()");
Log.i(LOG_TAG, "onCancelLoad()" + FusedPrintersProvider.this.hashCode());
}
return cancelInternal();
}
private boolean cancelInternal() {
if (mDiscoverySession != null && mDiscoverySession.isStarted()) {
if (mDiscoverySession != null
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
mDiscoverySession.stopPrinterDiscovery();
return true;
} else if (mPersistenceManager.isReadHistoryInProgress()) {
@@ -165,7 +177,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected void onReset() {
if (DEBUG) {
Log.i(LOG_TAG, "onReset()");
Log.i(LOG_TAG, "onReset()" + FusedPrintersProvider.this.hashCode());
}
onStopLoading();
mPrinters.clear();
@@ -178,73 +190,15 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected void onAbandon() {
if (DEBUG) {
Log.i(LOG_TAG, "onAbandon()");
Log.i(LOG_TAG, "onAbandon()" + FusedPrintersProvider.this.hashCode());
}
onStopLoading();
}
public void refreshPrinter(PrinterId printerId) {
if (isStarted() && mDiscoverySession != null && mDiscoverySession.isStarted()) {
mDiscoverySession.requestPrinterUpdated(printerId);
}
}
private final class MyPrinterDiscoverySession extends PrinterDiscoverySession {
@Override
public void onPrintersAdded(List<PrinterInfo> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "MyPrinterDiscoverySession#onPrintersAdded()");
}
boolean printersAdded = false;
final int addedPrinterCount = printers.size();
for (int i = 0; i < addedPrinterCount; i++) {
PrinterInfo printer = printers.get(i);
if (!mPrinters.containsKey(printer.getId())) {
mPrinters.put(printer.getId(), printer);
printersAdded = true;
}
}
if (printersAdded) {
deliverResult(new ArrayList<PrinterInfo>(mPrinters.values()));
}
}
@Override
public void onPrintersRemoved(List<PrinterId> printerIds) {
if (DEBUG) {
Log.i(LOG_TAG, "MyPrinterDiscoverySession#onPrintersRemoved()");
}
boolean removedPrinters = false;
final int removedPrinterCount = printerIds.size();
for (int i = 0; i < removedPrinterCount; i++) {
PrinterId removedPrinterId = printerIds.get(i);
if (mPrinters.remove(removedPrinterId) != null) {
removedPrinters = true;
}
}
if (removedPrinters) {
deliverResult(new ArrayList<PrinterInfo>(mPrinters.values()));
}
}
@Override
public void onPrintersUpdated(List<PrinterInfo> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "MyPrinterDiscoverySession#onPrintersUpdated()");
}
boolean updatedPrinters = false;
final int updatedPrinterCount = printers.size();
for (int i = 0; i < updatedPrinterCount; i++) {
PrinterInfo updatedPrinter = printers.get(i);
if (mPrinters.containsKey(updatedPrinter.getId())) {
mPrinters.put(updatedPrinter.getId(), updatedPrinter);
updatedPrinters = true;
}
}
if (updatedPrinters) {
deliverResult(new ArrayList<PrinterInfo>(mPrinters.values()));
}
if (isStarted() && mDiscoverySession != null
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
mDiscoverySession.requestPrinterUpdate(printerId);
}
}
@@ -280,7 +234,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
@Override
protected void onPostExecute(List<PrinterInfo> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "read history completed");
Log.i(LOG_TAG, "read history completed" + FusedPrintersProvider.this.hashCode());
}
mHistoricalPrinters = printers;
@@ -290,7 +244,7 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
// We want the first few favorite printers on top of the list.
final int favoriteCount = Math.min(mFavoritePrinters.size(),
MAX_HISTORICAL_PRINTER_COUNT);
MAX_FAVORITE_PRINTER_COUNT);
for (int i = 0; i < favoriteCount; i++) {
PrinterInfo favoritePrinter = mFavoritePrinters.get(i);
mPrinters.put(favoritePrinter.getId(), favoritePrinter);
@@ -299,6 +253,10 @@ public class FusedPrintersProvider extends Loader<List<PrinterInfo>> {
mReadHistoryInProgress = false;
mReadHistoryCompleted = true;
// Deliver the favorites.
deliverResult(mFavoritePrinters);
// Start loading the available printers.
loadInternal();
}

View File

@@ -64,7 +64,6 @@ import android.view.View.MeasureSpec;
import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
@@ -111,15 +110,10 @@ public class PrintJobConfigActivity extends Activity {
private static final int LOADER_ID_PRINTERS_LOADER = 1;
private static final int DEST_ADAPTER_MIN_ITEM_COUNT = 2;
private static final int DEST_ADAPTER_MAX_ITEM_COUNT = 9;
private static final int DEST_ADAPTER_POSITION_SEARCHING_FOR_PRINTERS = 0;
private static final int DEST_ADAPTER_POSITION_SAVE_AS_PDF = 1;
private static final int DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF = Integer.MAX_VALUE;
private static final int DEST_ADAPTER_ITEM_ID_ALL_PRINTERS = Integer.MAX_VALUE - 1;
private static final int DEST_ADAPTER_ITEM_ID_SEARCHING_FOR_PRINTERS = Integer.MAX_VALUE - 2;
private static final int ACTIVITY_REQUEST_CREATE_FILE = 1;
private static final int ACTIVITY_REQUEST_SELECT_PRINTER = 2;
@@ -196,15 +190,11 @@ public class PrintJobConfigActivity extends Activity {
setContentView(R.layout.print_job_config_activity_container);
// TODO: This should be on the style
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
mEditor = new Editor();
mDocument = new Document();
mController = new PrintController(new RemotePrintDocumentAdapter(
IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
PrintSpoolerService.peekInstance().generateFileForPrintJob(mPrintJobId)));
mEditor = new Editor();
try {
mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
@@ -217,6 +207,12 @@ public class PrintJobConfigActivity extends Activity {
mEditor.initialize();
}
@Override
public void onResume() {
super.onResume();
mEditor.refreshCurrentPrinter();
}
@Override
protected void onDestroy() {
// We can safely do the work in here since at this point
@@ -294,6 +290,8 @@ public class PrintJobConfigActivity extends Activity {
private int mControllerState = CONTROLLER_STATE_INITIALIZED;
private boolean mHasStarted;
private PageRange[] mRequestedPages;
public PrintController(RemotePrintDocumentAdapter adapter) {
@@ -305,6 +303,7 @@ public class PrintJobConfigActivity extends Activity {
}
public void initialize() {
mHasStarted = false;
mControllerState = CONTROLLER_STATE_INITIALIZED;
}
@@ -321,7 +320,7 @@ public class PrintJobConfigActivity extends Activity {
}
public boolean hasStarted() {
return mControllerState >= CONTROLLER_STATE_STARTED;
return mHasStarted;
}
public boolean hasPerformedLayout() {
@@ -335,10 +334,14 @@ public class PrintJobConfigActivity extends Activity {
public void start() {
mControllerState = CONTROLLER_STATE_STARTED;
mHasStarted = true;
mRemotePrintAdapter.start();
}
public void update() {
if (!mController.hasStarted()) {
mController.start();
}
if (!printAttributesChanged()) {
// If the attributes changed, then we do not do a layout but may
// have to ask the app to write some pages. Hence, pretend layout
@@ -372,6 +375,7 @@ public class PrintJobConfigActivity extends Activity {
}
if (isCancelled()) {
mEditor.updateUi();
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
}
@@ -379,7 +383,6 @@ public class PrintJobConfigActivity extends Activity {
}
mControllerState = CONTROLLER_STATE_LAYOUT_COMPLETED;
mEditor.updateUi();
// If the info changed, we update the document and the print job.
final boolean infoChanged = !info.equals(mDocument.info);
@@ -402,6 +405,7 @@ public class PrintJobConfigActivity extends Activity {
// trigger an update.
mRequestedPages = mEditor.getRequestedPages();
if (mRequestedPages == null) {
mEditor.updateUi();
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
}
@@ -423,12 +427,15 @@ public class PrintJobConfigActivity extends Activity {
// preview button, then just skip the write.
if (!LIVE_PREVIEW_SUPPORTED && !mEditor.isPreviewConfirmed()
&& mMetadata.getBoolean(PrintDocumentAdapter.METADATA_KEY_PRINT_PREVIEW)) {
mEditor.updateUi();
if (mEditor.isDone()) {
PrintJobConfigActivity.this.finish();
}
return;
}
mEditor.updateUi();
// Request a write of the pages of interest.
mControllerState = CONTROLLER_STATE_WRITE_STARTED;
mRemotePrintAdapter.write(mRequestedPages, mWriteResultCallback,
@@ -647,7 +654,6 @@ public class PrintJobConfigActivity extends Activity {
if (resultCode == RESULT_OK) {
PrinterId printerId = (PrinterId) data.getParcelableExtra(
INTENT_EXTRA_PRINTER_ID);
// TODO: Make sure the selected printer is in the shown list.
mEditor.selectPrinter(printerId);
}
} break;
@@ -704,8 +710,9 @@ public class PrintJobConfigActivity extends Activity {
private EditText mCopiesEditText;
private TextView mRangeTitle;
private EditText mRangeEditText;
private TextView mRangeOptionsTitle;
private TextView mPageRangeTitle;
private EditText mPageRangeEditText;
private Spinner mDestinationSpinner;
private final DestinationAdapter mDestinationSpinnerAdapter;
@@ -729,6 +736,8 @@ public class PrintJobConfigActivity extends Activity {
private Button mPrintButton;
private PrinterInfo mCurrentPrinter;
private final OnItemSelectedListener mOnItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@Override
@@ -738,69 +747,37 @@ public class PrintJobConfigActivity extends Activity {
mIgnoreNextDestinationChange = false;
return;
}
if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
mIgnoreNextDestinationChange = true;
mDestinationSpinner.setSelection(0);
Intent intent = new Intent(PrintJobConfigActivity.this,
SelectPrinterActivity.class);
startActivityForResult(intent, ACTIVITY_REQUEST_SELECT_PRINTER);
startSelectPrinterActivity();
return;
}
mWaitingForPrinterCapabilities = false;
mCurrPrintAttributes.clear();
PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter
.getItem(position);
PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence(
mPrintJobId, printer);
if (printer != null) {
PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence(
mPrintJobId, printer);
PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
if (capabilities == null) {
List<PrinterId> printerIds = new ArrayList<PrinterId>();
printerIds.add(printer.getId());
FusedPrintersProvider printersLoader = (FusedPrintersProvider)
(Loader<?>) getLoaderManager().getLoader(
LOADER_ID_PRINTERS_LOADER);
if (printersLoader != null) {
printersLoader.refreshPrinter(printer.getId());
}
mWaitingForPrinterCapabilities = true;
//TODO: We need a timeout for the update.
mEditor.refreshCurrentPrinter();
} else {
capabilities.getDefaults(mCurrPrintAttributes);
if (!mController.hasStarted()) {
mController.start();
}
if (!hasErrors()) {
mController.update();
}
mController.update();
}
}
// The printer changed so we want to start with a clean slate
// for the print options and let them be populated from the
// printer capabilities and use the printer defaults.
if (!mMediaSizeSpinnerAdapter.isEmpty()) {
mIgnoreNextMediaSizeChange = true;
mMediaSizeSpinnerAdapter.clear();
}
if (!mColorModeSpinnerAdapter.isEmpty()) {
mIgnoreNextColorModeChange = true;
mColorModeSpinnerAdapter.clear();
}
if (!mOrientationSpinnerAdapter.isEmpty()) {
mIgnoreNextOrientationChange = true;
mOrientationSpinnerAdapter.clear();
}
if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
mIgnoreNextRangeOptionChange = true;
mRangeOptionsSpinner.setSelection(0);
}
if (!TextUtils.isEmpty(mCopiesEditText.getText())) {
mIgnoreNextCopiesChange = true;
mCopiesEditText.setText(MIN_COPIES_STRING);
}
mCurrentPrinter = printer;
updateUi();
updateUiForNewPrinterCapabilities();
} else if (spinner == mMediaSizeSpinner) {
if (mIgnoreNextMediaSizeChange) {
mIgnoreNextMediaSizeChange = false;
@@ -877,7 +854,13 @@ public class PrintJobConfigActivity extends Activity {
return;
}
final int copies = Integer.parseInt(editable.toString());
int copies = 0;
try {
copies = Integer.parseInt(editable.toString());
} catch (NumberFormatException nfe) {
/* ignore */
}
if (copies < MIN_COPIES) {
mCopiesEditText.setError("");
updateUi();
@@ -918,14 +901,14 @@ public class PrintJobConfigActivity extends Activity {
String text = editable.toString();
if (TextUtils.isEmpty(text)) {
mRangeEditText.setError("");
mPageRangeEditText.setError("");
updateUi();
return;
}
String escapedText = PATTERN_ESCAPE_SPECIAL_CHARS.matcher(text).replaceAll("////");
if (!PATTERN_PAGE_RANGE.matcher(escapedText).matches()) {
mRangeEditText.setError("");
mPageRangeEditText.setError("");
updateUi();
return;
}
@@ -935,7 +918,7 @@ public class PrintJobConfigActivity extends Activity {
String numericString = text.substring(matcher.start(), matcher.end());
final int pageIndex = Integer.parseInt(numericString);
if (pageIndex < 1 || pageIndex > mDocument.info.getPageCount()) {
mRangeEditText.setError("");
mPageRangeEditText.setError("");
updateUi();
return;
}
@@ -943,7 +926,7 @@ public class PrintJobConfigActivity extends Activity {
//TODO: Catch the error if start is less grater than the end.
mRangeEditText.setError(null);
mPageRangeEditText.setError(null);
mPrintButton.setEnabled(true);
updateUi();
@@ -963,45 +946,70 @@ public class PrintJobConfigActivity extends Activity {
private boolean mIgnoreNextCopiesChange;
private boolean mIgnoreNextRangeChange;
private boolean mWaitingForPrinterCapabilities;
private int mCurrentUi = UI_NONE;
private boolean mFavoritePrinterSelected;
public Editor() {
// Destination.
mDestinationSpinnerAdapter = new DestinationAdapter();
mDestinationSpinnerAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
final int selectedPosition = mDestinationSpinner.getSelectedItemPosition();
if (mDestinationSpinnerAdapter.getCount() > 0) {
// Make sure we select the first printer if we have data.
if (selectedPosition == AdapterView.INVALID_POSITION) {
mDestinationSpinner.setSelection(0);
}
} else {
// Make sure we select no printer if we have no data.
mDestinationSpinner.setSelection(AdapterView.INVALID_POSITION);
// Initially, we have only sage to PDF as a printer but after some
// printers are loaded we want to select the user's favorite one
// which is the first.
if (!mFavoritePrinterSelected && mDestinationSpinnerAdapter.getCount() > 2) {
mFavoritePrinterSelected = true;
mDestinationSpinner.setSelection(0);
}
// 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 && printer.getCapabilities() != null) {
mOnItemSelectedListener.onItemSelected(mDestinationSpinner, null,
selectedPosition, selectedPosition);
// If the current printer properties changed, we update the UI.
if (mCurrentPrinter != null) {
final int printerCount = mDestinationSpinnerAdapter.getCount();
for (int i = 0; i < printerCount; i++) {
Object item = mDestinationSpinnerAdapter.getItem(i);
// Some items are not printers
if (item instanceof PrinterInfo) {
PrinterInfo printer = (PrinterInfo) item;
if (!printer.getId().equals(mCurrentPrinter.getId())) {
continue;
}
// Update the UI if capabilities changed.
boolean capabilitiesChanged = false;
if (mCurrentPrinter.getCapabilities() == null) {
if (printer.getCapabilities() != null) {
capabilitiesChanged = true;
}
} else if (!mCurrentPrinter.getCapabilities().equals(
printer.getCapabilities())) {
capabilitiesChanged = true;
}
if (capabilitiesChanged) {
// Update the current printer.
mCurrentPrinter.copyFrom(printer);
// If something changed during UI update...
if (updateUi()) {
// Update current attributes.
printer.getCapabilities().getDefaults(mCurrPrintAttributes);
// Update the document.
mController.update();
}
}
break;
}
}
}
updateUi();
}
@Override
public void onInvalidated() {
updateUi();
updateUiForNewPrinterCapabilities();
}
});
@@ -1039,17 +1047,24 @@ public class PrintJobConfigActivity extends Activity {
updateUi();
}
public void selectPrinter(PrinterId printerId) {
final int printerCount = mDestinationSpinnerAdapter.getCount();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = (PrinterInfo) mDestinationSpinnerAdapter.getItem(i);
if (printer.getId().equals(printerId)) {
mDestinationSpinner.setSelection(i);
return;
public void refreshCurrentPrinter() {
PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
if (printer != null) {
FusedPrintersProvider printersLoader = (FusedPrintersProvider)
(Loader<?>) getLoaderManager().getLoader(
LOADER_ID_PRINTERS_LOADER);
if (printersLoader != null) {
printersLoader.refreshPrinter(printer.getId());
}
}
}
public void selectPrinter(PrinterId printerId) {
mDestinationSpinnerAdapter.ensurePrinterShownPrinterShown(printerId);
final int position = mDestinationSpinnerAdapter.getPrinterIndex(printerId);
mDestinationSpinner.setSelection(position);
}
public boolean isPrintingToPdf() {
return mDestinationSpinner.getSelectedItem()
== mDestinationSpinnerAdapter.mFakePdfPrinter;
@@ -1163,12 +1178,7 @@ public class PrintJobConfigActivity extends Activity {
mEditor.confirmPrint();
mController.update();
if (!printer.equals(mDestinationSpinnerAdapter.mFakePdfPrinter)) {
FusedPrintersProvider printersLoader = (FusedPrintersProvider)
(Loader<?>) getLoaderManager().getLoader(
LOADER_ID_PRINTERS_LOADER);
if (printersLoader != null) {
printersLoader.addHistoricalPrinter(printer);
}
mEditor.refreshCurrentPrinter();
}
} else {
mEditor.cancel();
@@ -1288,7 +1298,7 @@ public class PrintJobConfigActivity extends Activity {
}
if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
List<PageRange> pageRanges = new ArrayList<PageRange>();
mStringCommaSplitter.setString(mRangeEditText.getText().toString());
mStringCommaSplitter.setString(mPageRangeEditText.getText().toString());
while (mStringCommaSplitter.hasNext()) {
String range = mStringCommaSplitter.next().trim();
@@ -1340,7 +1350,7 @@ public class PrintJobConfigActivity extends Activity {
mDestinationSpinner = (Spinner) findViewById(R.id.destination_spinner);
mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
if (mDestinationSpinnerAdapter.getCount() > 0) {
if (mDestinationSpinnerAdapter.getCount() > 0 && mController.hasStarted()) {
mIgnoreNextDestinationChange = true;
}
@@ -1368,12 +1378,8 @@ public class PrintJobConfigActivity extends Activity {
mIgnoreNextOrientationChange = true;
}
// Range
mRangeTitle = (TextView) findViewById(R.id.page_range_title);
mRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
mRangeEditText.addTextChangedListener(mRangeTextWatcher);
// Range options
mRangeOptionsTitle = (TextView) findViewById(R.id.range_options_title);
mRangeOptionsSpinner = (Spinner) findViewById(R.id.range_options_spinner);
mRangeOptionsSpinner.setAdapter(mRangeOptionsSpinnerAdapter);
mRangeOptionsSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
@@ -1381,14 +1387,19 @@ public class PrintJobConfigActivity extends Activity {
mIgnoreNextRangeOptionChange = true;
}
// Page range
mPageRangeTitle = (TextView) findViewById(R.id.page_range_title);
mPageRangeEditText = (EditText) findViewById(R.id.page_range_edittext);
mPageRangeEditText.addTextChangedListener(mRangeTextWatcher);
// Print button
mPrintButton = (Button) findViewById(R.id.print_button);
registerPrintButtonClickListener();
}
public void updateUi() {
public boolean updateUi() {
if (mCurrentUi != UI_EDITING_PRINT_JOB) {
return;
return false;
}
if (isPrintConfirmed() || isPreviewConfirmed() || isCancelled()) {
mDestinationSpinner.setEnabled(false);
@@ -1397,11 +1408,11 @@ public class PrintJobConfigActivity extends Activity {
mColorModeSpinner.setEnabled(false);
mOrientationSpinner.setEnabled(false);
mRangeOptionsSpinner.setEnabled(false);
mRangeEditText.setEnabled(false);
mPageRangeEditText.setEnabled(false);
// TODO: Remove entirely or implement print preview.
// mPrintPreviewButton.setEnabled(false);
mPrintButton.setEnabled(false);
return;
return false;
}
// If a printer with capabilities is selected, then we enabled all options.
@@ -1452,15 +1463,16 @@ public class PrintJobConfigActivity extends Activity {
mRangeOptionsSpinner.setSelection(0);
}
mRangeOptionsSpinner.setEnabled(false);
mRangeTitle.setText(getString(R.string.label_pages,
mRangeOptionsTitle.setText(getString(R.string.label_pages,
getString(R.string.page_count_unknown)));
if (!TextUtils.equals(mRangeEditText.getText(), "")) {
if (!TextUtils.equals(mPageRangeEditText.getText(), "")) {
mIgnoreNextRangeChange = true;
mRangeEditText.setText("");
mPageRangeEditText.setText("");
}
mRangeEditText.setEnabled(false);
mRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeEditText.setEnabled(false);
mPageRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeTitle.setVisibility(View.INVISIBLE);
// // Print preview
// mPrintPreviewButton.setEnabled(false);
@@ -1468,17 +1480,20 @@ public class PrintJobConfigActivity extends Activity {
// Print
mPrintButton.setEnabled(false);
return false;
} else {
boolean someAttributeSelectionChanged = false;
PrintAttributes defaultAttributes = mTempPrintAttributes;
PrinterInfo printer = (PrinterInfo) mDestinationSpinner.getSelectedItem();
PrinterCapabilitiesInfo capabilities = printer.getCapabilities();
printer.getCapabilities().getDefaults(defaultAttributes);
// Copies
mCopiesEditText.setEnabled(true);
// Media size.
List<MediaSize> mediaSizes = capabilities.getMediaSizes();
// If the media sizes changed, we update the adapter and the spinner.
boolean mediaSizesChanged = false;
final int mediaSizeCount = mediaSizes.size();
if (mediaSizeCount != mMediaSizeSpinnerAdapter.getCount()) {
@@ -1492,22 +1507,40 @@ public class PrintJobConfigActivity extends Activity {
}
}
if (mediaSizesChanged) {
// Remember the old media size to try selecting it again.
int oldMediaSizeNewIndex = AdapterView.INVALID_POSITION;
MediaSize oldMediaSize = mCurrPrintAttributes.getMediaSize();
// Rebuild the adapter data.
mMediaSizeSpinnerAdapter.clear();
for (int i = 0; i < mediaSizeCount; i++) {
MediaSize mediaSize = mediaSizes.get(i);
if (mediaSize.equals(oldMediaSize)) {
// Update the index of the old selection.
oldMediaSizeNewIndex = i;
}
mMediaSizeSpinnerAdapter.add(new SpinnerItem<MediaSize>(
mediaSize, mediaSize.getLabel()));
}
if (mediaSizeCount <= 0) {
// No media sizes - clear the selection.
mMediaSizeSpinner.setEnabled(false);
mMediaSizeSpinner.setSelection(AdapterView.INVALID_POSITION);
// Clear selection and mark if selection changed.
someAttributeSelectionChanged = setMediaSizeSpinnerSelectionNoCallback(
AdapterView.INVALID_POSITION);
} else {
mMediaSizeSpinner.setEnabled(true);
final int selectedMediaSizeIndex = Math.max(mediaSizes.indexOf(
defaultAttributes.getMediaSize()), 0);
if (mMediaSizeSpinner.getSelectedItemPosition() != selectedMediaSizeIndex) {
mIgnoreNextMediaSizeChange = true;
mMediaSizeSpinner.setSelection(selectedMediaSizeIndex);
if (oldMediaSizeNewIndex != AdapterView.INVALID_POSITION) {
// Select the old media size - nothing really changed.
setMediaSizeSpinnerSelectionNoCallback(oldMediaSizeNewIndex);
} else {
// Select the first or the default and mark if selection changed.
final int mediaSizeIndex = Math.max(mediaSizes.indexOf(
defaultAttributes.getMediaSize()), 0);
someAttributeSelectionChanged = setMediaSizeSpinnerSelectionNoCallback(
mediaSizeIndex);
}
}
}
@@ -1619,20 +1652,22 @@ public class PrintJobConfigActivity extends Activity {
|| info.getPageCount() == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)) {
mRangeOptionsSpinner.setEnabled(true);
if (mRangeOptionsSpinner.getSelectedItemPosition() > 0) {
if (!mRangeEditText.isEnabled()) {
mRangeEditText.setEnabled(true);
mRangeEditText.setVisibility(View.VISIBLE);
mRangeEditText.requestFocus();
if (!mPageRangeEditText.isEnabled()) {
mPageRangeEditText.setEnabled(true);
mPageRangeEditText.setVisibility(View.VISIBLE);
mPageRangeTitle.setVisibility(View.VISIBLE);
mPageRangeEditText.requestFocus();
InputMethodManager imm = (InputMethodManager)
getSystemService(INPUT_METHOD_SERVICE);
imm.showSoftInput(mRangeEditText, 0);
imm.showSoftInput(mPageRangeEditText, 0);
}
} else {
mRangeEditText.setEnabled(false);
mRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeEditText.setEnabled(false);
mPageRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeTitle.setVisibility(View.INVISIBLE);
}
final int pageCount = mDocument.info.getPageCount();
mRangeTitle.setText(getString(R.string.label_pages,
mRangeOptionsTitle.setText(getString(R.string.label_pages,
(pageCount == PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
? getString(R.string.page_count_unknown)
: String.valueOf(pageCount)));
@@ -1642,16 +1677,29 @@ public class PrintJobConfigActivity extends Activity {
mRangeOptionsSpinner.setSelection(0);
}
mRangeOptionsSpinner.setEnabled(false);
mRangeTitle.setText(getString(R.string.label_pages,
mRangeOptionsTitle.setText(getString(R.string.label_pages,
getString(R.string.page_count_unknown)));
mRangeEditText.setEnabled(false);
mRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeEditText.setEnabled(false);
mPageRangeEditText.setVisibility(View.INVISIBLE);
mPageRangeTitle.setVisibility(View.INVISIBLE);
}
mRangeOptionsSpinner.setEnabled(true);
// Print/Print preview
if (mDestinationSpinner.getSelectedItemId()
!= DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF) {
String newText = getString(R.string.print_button);
if (!TextUtils.equals(newText, mPrintButton.getText())) {
mPrintButton.setText(R.string.print_button);
}
} else {
String newText = getString(R.string.save_button);
if (!TextUtils.equals(newText, mPrintButton.getText())) {
mPrintButton.setText(R.string.save_button);
}
}
if ((mRangeOptionsSpinner.getSelectedItemPosition() == 1
&& (TextUtils.isEmpty(mRangeEditText.getText()) || hasErrors()))
&& (TextUtils.isEmpty(mPageRangeEditText.getText()) || hasErrors()))
|| (mRangeOptionsSpinner.getSelectedItemPosition() == 0
&& (!mController.hasPerformedLayout() || hasErrors()))) {
// mPrintPreviewButton.setEnabled(false);
@@ -1667,6 +1715,12 @@ public class PrintJobConfigActivity extends Activity {
}
// Copies
if (mDestinationSpinner.getSelectedItemId()
!= DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF) {
mCopiesEditText.setEnabled(true);
} else {
mCopiesEditText.setEnabled(false);
}
if (mCopiesEditText.getError() == null
&& TextUtils.isEmpty(mCopiesEditText.getText())) {
mIgnoreNextCopiesChange = true;
@@ -1674,13 +1728,62 @@ public class PrintJobConfigActivity extends Activity {
mCopiesEditText.selectAll();
mCopiesEditText.requestFocus();
}
mCopiesEditText.setEnabled(true);
return someAttributeSelectionChanged;
}
}
private boolean setMediaSizeSpinnerSelectionNoCallback(int position) {
if (mMediaSizeSpinner.getSelectedItemPosition() != position) {
mIgnoreNextMediaSizeChange = true;
mMediaSizeSpinner.setSelection(position);
return true;
}
return false;
}
private void updateUiForNewPrinterCapabilities() {
// The printer changed so we want to start with a clean slate
// for the print options and let them be populated from the
// printer capabilities and use the printer defaults.
if (!mMediaSizeSpinnerAdapter.isEmpty()) {
mIgnoreNextMediaSizeChange = true;
mMediaSizeSpinnerAdapter.clear();
}
if (!mColorModeSpinnerAdapter.isEmpty()) {
mIgnoreNextColorModeChange = true;
mColorModeSpinnerAdapter.clear();
}
if (!mOrientationSpinnerAdapter.isEmpty()) {
mIgnoreNextOrientationChange = true;
mOrientationSpinnerAdapter.clear();
}
if (mRangeOptionsSpinner.getSelectedItemPosition() != 0) {
mIgnoreNextRangeOptionChange = true;
mRangeOptionsSpinner.setSelection(0);
}
if (!TextUtils.isEmpty(mCopiesEditText.getText())) {
mIgnoreNextCopiesChange = true;
mCopiesEditText.setText(MIN_COPIES_STRING);
}
updateUi();
}
private void startSelectPrinterActivity() {
mIgnoreNextDestinationChange = true;
mDestinationSpinner.setSelection(0);
Intent intent = new Intent(PrintJobConfigActivity.this,
SelectPrinterActivity.class);
startActivityForResult(intent, ACTIVITY_REQUEST_SELECT_PRINTER);
}
private boolean hasErrors() {
return mRangeEditText.getError() != null
|| mCopiesEditText.getError() != null;
if (mCopiesEditText.getError() != null) {
return true;
}
return mPageRangeEditText.getVisibility() == View.VISIBLE
&& mPageRangeEditText.getError() != null;
}
// private boolean hasPdfViewer() {
@@ -1708,29 +1811,49 @@ public class PrintJobConfigActivity extends Activity {
implements LoaderManager.LoaderCallbacks<List<PrinterInfo>>{
private final List<PrinterInfo> mPrinters = new ArrayList<PrinterInfo>();
public final PrinterInfo mFakePdfPrinter;
private final PrinterInfo mFakePdfPrinter;
private PrinterId mLastShownPrinterId;
public DestinationAdapter() {
getLoaderManager().initLoader(LOADER_ID_PRINTERS_LOADER, null, this);
mFakePdfPrinter = createFakePdfPrinter();
}
public int getPrinterIndex(PrinterId printerId) {
for (int i = 0; i < getCount(); i++) {
PrinterInfo printer = (PrinterInfo) getItem(i);
if (printer != null && printer.getId().equals(printerId)) {
return i;
}
}
return AdapterView.INVALID_POSITION;
}
public void ensurePrinterShownPrinterShown(PrinterId printerId) {
mLastShownPrinterId = printerId;
ensureLastShownPrinterInPosition();
}
@Override
public int getCount() {
return Math.max(Math.min(mPrinters.size(), DEST_ADAPTER_MAX_ITEM_COUNT),
DEST_ADAPTER_MIN_ITEM_COUNT);
return Math.min(mPrinters.size() + 2, DEST_ADAPTER_MAX_ITEM_COUNT);
}
@Override
public Object getItem(int position) {
if (position == DEST_ADAPTER_POSITION_SAVE_AS_PDF) {
return mFakePdfPrinter;
}
if (!mPrinters.isEmpty()) {
if (position < DEST_ADAPTER_POSITION_SAVE_AS_PDF) {
if (mPrinters.isEmpty()) {
if (position == 0) {
return mFakePdfPrinter;
}
} else {
if (position < 1) {
return mPrinters.get(position);
} else if (position > DEST_ADAPTER_POSITION_SAVE_AS_PDF
&& position < getCount() - 1) {
}
if (position == 1) {
return mFakePdfPrinter;
}
if (position < getCount() - 1) {
return mPrinters.get(position - 1);
}
}
@@ -1739,15 +1862,17 @@ public class PrintJobConfigActivity extends Activity {
@Override
public long getItemId(int position) {
if (position == DEST_ADAPTER_POSITION_SAVE_AS_PDF) {
return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
}
if (mPrinters.isEmpty()) {
if (position == DEST_ADAPTER_POSITION_SEARCHING_FOR_PRINTERS) {
return DEST_ADAPTER_ITEM_ID_SEARCHING_FOR_PRINTERS;
if (position == 0) {
return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
}
} else {
if (position == 1) {
return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
}
if (position == getCount() - 1) {
return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
}
} else if (position == getCount() - 1) {
return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
}
return position;
}
@@ -1768,11 +1893,15 @@ public class PrintJobConfigActivity extends Activity {
CharSequence title = null;
CharSequence subtitle = null;
if (mPrinters.isEmpty()
&& position == DEST_ADAPTER_POSITION_SEARCHING_FOR_PRINTERS) {
title = getString(R.string.searching_for_printers);
if (mPrinters.isEmpty()) {
if (position == 0) {
PrinterInfo printer = (PrinterInfo) getItem(position);
title = printer.getName();
} else if (position == 1) {
title = getString(R.string.all_printers);
}
} else {
if (position == DEST_ADAPTER_POSITION_SAVE_AS_PDF) {
if (position == 1) {
PrinterInfo printer = (PrinterInfo) getItem(position);
title = printer.getName();
} else if (position == getCount() - 1) {
@@ -1818,6 +1947,7 @@ public class PrintJobConfigActivity extends Activity {
List<PrinterInfo> printers) {
mPrinters.clear();
mPrinters.addAll(printers);
ensureLastShownPrinterInPosition();
notifyDataSetChanged();
}
@@ -1827,6 +1957,27 @@ public class PrintJobConfigActivity extends Activity {
notifyDataSetInvalidated();
}
private void ensureLastShownPrinterInPosition() {
if (mLastShownPrinterId == null) {
return;
}
final int printerCount = mPrinters.size();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = (PrinterInfo) mPrinters.get(i);
if (printer.getId().equals(mLastShownPrinterId)) {
// If already in the list - do nothing.
if (i < getCount() - 1) {
return;
}
// Else replace the last one.
final int lastPrinter = getCount() - 2;
mPrinters.set(i, mPrinters.get(lastPrinter - 1));
mPrinters.set(lastPrinter - 1, printer);
return;
}
}
}
private PrinterInfo createFakePdfPrinter() {
PrinterId printerId = new PrinterId(getComponentName(), "PDF printer");

View File

@@ -103,8 +103,6 @@ public final class PrintSpoolerService extends Service {
private NotificationController mNotificationController;
private PrinterDiscoverySession mDiscoverySession;
public static PrintSpoolerService peekInstance() {
synchronized (sLock) {
return sInstance;
@@ -225,61 +223,9 @@ public final class PrintSpoolerService extends Service {
HandlerCallerCallback.MSG_SET_CLIENT, client);
mHandlerCaller.executeOrSendMessage(message);
}
@Override
public void onPrintersAdded(List<PrinterInfo> printers) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINTERS_ADDED, printers);
mHandlerCaller.executeOrSendMessage(message);
}
@Override
public void onPrintersRemoved(List<PrinterId> printerIds) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINTERS_REMOVED, printerIds);
mHandlerCaller.executeOrSendMessage(message);
}
@Override
public void onPrintersUpdated(List<PrinterInfo> printers) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINTERS_UPDATED, printers);
mHandlerCaller.executeOrSendMessage(message);
}
};
}
public void createPrinterDiscoverySession() {
Message message = mHandlerCaller.obtainMessage(
HandlerCallerCallback.MSG_CREATE_PRINTER_DISCOVERY_SESSION);
mHandlerCaller.executeOrSendMessage(message);
}
public void destroyPrinterDiscoverySession() {
Message message = mHandlerCaller.obtainMessage(
HandlerCallerCallback.MSG_DESTROY_PRINTER_DISCOVERY_SESSION);
mHandlerCaller.executeOrSendMessage(message);
}
public void startPrinterDiscovery(List<PrinterId> priorityList) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_START_PRINTER_DISCOVERY, priorityList);
mHandlerCaller.executeOrSendMessage(message);
}
public void stopPrinterDiscovery() {
Message message = mHandlerCaller.obtainMessage(
HandlerCallerCallback.MSG_STOP_PRINTER_DISCOVERY);
mHandlerCaller.executeOrSendMessage(message);
}
public void requestPrinterUpdate(PrinterId pritnerId) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_REQUEST_PRINTER_UPDATE, pritnerId);
mHandlerCaller.executeOrSendMessage(message);
}
private void sendOnPrintJobQueued(PrintJobInfo printJob) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_QUEUED, printJob);
@@ -299,16 +245,6 @@ public final class PrintSpoolerService extends Service {
}
private final class HandlerCallerCallback implements HandlerCaller.Callback {
public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 1;
public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 2;
public static final int MSG_START_PRINTER_DISCOVERY = 3;
public static final int MSG_STOP_PRINTER_DISCOVERY = 4;
public static final int MSG_REQUEST_PRINTER_UPDATE = 5;
public static final int MSG_ON_PRINTERS_ADDED = 6;
public static final int MSG_ON_PRINTERS_REMOVED = 7;
public static final int MSG_ON_PRINTERS_UPDATED = 8;
public static final int MSG_SET_CLIENT = 9;
public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 10;
public static final int MSG_ON_PRINT_JOB_QUEUED = 11;
@@ -317,81 +253,8 @@ public final class PrintSpoolerService extends Service {
public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 14;
@Override
@SuppressWarnings("unchecked")
public void executeMessage(Message message) {
switch (message.what) {
case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
final IPrintSpoolerClient client;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
try {
client.createPrinterDiscoverySession();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error creating printer discovery session.", re);
}
}
} break;
case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
final IPrintSpoolerClient client;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
try {
client.destroyPrinterDiscoverySession();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error destroying printer discovery session.", re);
}
}
} break;
case MSG_START_PRINTER_DISCOVERY: {
final IPrintSpoolerClient client;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
List<PrinterId> priorityList = (ArrayList<PrinterId>) message.obj;
try {
client.startPrinterDiscovery(priorityList);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error starting printer discovery.", re);
}
}
} break;
case MSG_STOP_PRINTER_DISCOVERY: {
final IPrintSpoolerClient client;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
try {
client.stopPrinterDiscovery();
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error stopping printer discovery.", re);
}
}
} break;
case MSG_REQUEST_PRINTER_UPDATE: {
final IPrintSpoolerClient client;
synchronized (mLock) {
client = mClient;
}
if (client != null) {
PrinterId printerId = (PrinterId) message.obj;
try {
client.requestPrinterUpdate(printerId);
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error requesing printer update.", re);
}
}
} break;
case MSG_SET_CLIENT: {
synchronized (mLock) {
mClient = (IPrintSpoolerClient) message.obj;
@@ -452,39 +315,6 @@ public final class PrintSpoolerService extends Service {
case MSG_CHECK_ALL_PRINTJOBS_HANDLED: {
checkAllPrintJobsHandled();
} break;
case MSG_ON_PRINTERS_ADDED: {
final PrinterDiscoverySession session;
synchronized (mLock) {
session = mDiscoverySession;
}
if (session != null) {
List<PrinterInfo> printers = (ArrayList<PrinterInfo>) message.obj;
session.onPrintersAdded(printers);
}
} break;
case MSG_ON_PRINTERS_REMOVED: {
final PrinterDiscoverySession session;
synchronized (mLock) {
session = mDiscoverySession;
}
if (session != null) {
List<PrinterId> printerIds = (ArrayList<PrinterId>) message.obj;
session.onPrintersRemoved(printerIds);
}
} break;
case MSG_ON_PRINTERS_UPDATED: {
final PrinterDiscoverySession session;
synchronized (mLock) {
session = mDiscoverySession;
}
if (session != null) {
List<PrinterInfo> printers = (ArrayList<PrinterInfo>) message.obj;
session.onPrintersUpdated(printers);
}
} break;
}
}
}
@@ -583,12 +413,6 @@ public final class PrintSpoolerService extends Service {
}
}
private void setPrinterDiscoverySessionClient(PrinterDiscoverySession session) {
synchronized (mLock) {
mDiscoverySession = session;
}
}
private int generatePrintJobIdLocked() {
int printJobId = sPrintJobIdCounter++;
while (isDuplicatePrintJobId(printJobId)) {
@@ -1352,46 +1176,4 @@ public final class PrintSpoolerService extends Service {
return true;
}
}
public static abstract class PrinterDiscoverySession {
private PrintSpoolerService mService;
private boolean mIsStarted;
public PrinterDiscoverySession() {
mService = PrintSpoolerService.peekInstance();
mService.createPrinterDiscoverySession();
mService.setPrinterDiscoverySessionClient(this);
}
public final void startPrinterDisovery(List<PrinterId> priorityList) {
mIsStarted = true;
mService.startPrinterDiscovery(priorityList);
}
public final void stopPrinterDiscovery() {
mIsStarted = false;
mService.stopPrinterDiscovery();
}
public void requestPrinterUpdated(PrinterId printerId) {
mService.requestPrinterUpdate(printerId);
}
public final void destroy() {
mService.setPrinterDiscoverySessionClient(null);
mService.destroyPrinterDiscoverySession();
}
public final boolean isStarted() {
return mIsStarted;
}
public abstract void onPrintersAdded(List<PrinterInfo> printers);
public abstract void onPrintersRemoved(List<PrinterId> printerIds);
public abstract void onPrintersUpdated(List<PrinterInfo> printers);
}
}

View File

@@ -31,8 +31,10 @@ import android.os.UserHandle;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintManager;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.provider.Settings;
import android.util.SparseArray;
@@ -188,6 +190,84 @@ public final class PrintManagerService extends IPrintManager.Stub {
}
}
@Override
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.createPrinterDiscoverySession(observer);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.destroyPrinterDiscoverySession(observer);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
List<PrinterId> priorityList, int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.startPrinterDiscovery(observer, priorityList);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.stopPrinterDiscovery(observer);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
public void requestPrinterUpdate(PrinterId printerId, int userId) {
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
userState.requestPrinterUpdate(printerId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private void registerContentObservers() {
final Uri enabledPrintServicesUri = Settings.Secure.getUriFor(
Settings.Secure.ENABLED_PRINT_SERVICES);

View File

@@ -61,6 +61,8 @@ final class RemotePrintService implements DeathRecipient {
private final RemotePrintSpooler mSpooler;
private final UserState mUserState;
private final int mUserId;
private final List<Runnable> mPendingCommands = new ArrayList<Runnable>();
@@ -82,8 +84,9 @@ final class RemotePrintService implements DeathRecipient {
private boolean mHasPrinterDiscoverySession;
public RemotePrintService(Context context, ComponentName componentName, int userId,
RemotePrintSpooler spooler) {
RemotePrintSpooler spooler, UserState userState) {
mContext = context;
mUserState = userState;
mComponentName = componentName;
mIntent = new Intent().setComponent(mComponentName);
mUserId = userId;
@@ -561,7 +564,7 @@ final class RemotePrintService implements DeathRecipient {
throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
final long identity = Binder.clearCallingIdentity();
try {
service.mSpooler.onPrintersAdded(printers);
service.mUserState.onPrintersAdded(printers);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -575,7 +578,7 @@ final class RemotePrintService implements DeathRecipient {
throwIfPrinterIdsTampered(service.mComponentName, printerIds);
final long identity = Binder.clearCallingIdentity();
try {
service.mSpooler.onPrintersRemoved(printerIds);
service.mUserState.onPrintersRemoved(printerIds);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -589,7 +592,7 @@ final class RemotePrintService implements DeathRecipient {
throwIfPrinterIdsForPrinterInfoTampered(service.mComponentName, printers);
final long identity = Binder.clearCallingIdentity();
try {
service.mSpooler.onPrintersUpdated(printers);
service.mUserState.onPrintersUpdated(printers);
} finally {
Binder.restoreCallingIdentity(identity);
}

View File

@@ -34,8 +34,6 @@ import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
import android.print.PrintAttributes;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.util.Slog;
import android.util.TimedRemoteCaller;
@@ -93,11 +91,6 @@ final class RemotePrintSpooler {
public static interface PrintSpoolerCallbacks {
public void onPrintJobQueued(PrintJobInfo printJob);
public void onAllPrintJobsForServiceHandled(ComponentName printService);
public void createPrinterDiscoverySession();
public void destroyPrinterDiscoverySession();
public void startPrinterDiscovery(List<PrinterId> priorityList);
public void stopPrinterDiscovery();
public void requestPrinterUpdate(PrinterId printerId);
}
public RemotePrintSpooler(Context context, int userId,
@@ -305,78 +298,6 @@ final class RemotePrintSpooler {
}
}
public final void onPrintersAdded(List<PrinterInfo> printers) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
getRemoteInstanceLazy().onPrintersAdded(printers);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error adding printers.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error adding printers.", te);
} finally {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ "] onPrintersAdded()");
}
synchronized (mLock) {
mCanUnbind = true;
mLock.notifyAll();
}
}
}
public final void onPrintersRemoved(List<PrinterId> printerIds) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
getRemoteInstanceLazy().onPrintersRemoved(printerIds);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error removing printers.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error removing printers.", te);
} finally {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ "] onPrintersRemoved()");
}
synchronized (mLock) {
mCanUnbind = true;
mLock.notifyAll();
}
}
}
public final void onPrintersUpdated(List<PrinterInfo> printers) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
getRemoteInstanceLazy().onPrintersUpdated(printers);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error updating printers.", re);
} catch (TimeoutException te) {
Slog.e(LOG_TAG, "Error updating printers.", te);
} finally {
if (DEBUG) {
Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier()
+ "] onPrintersUpdted()");
}
synchronized (mLock) {
mCanUnbind = true;
mLock.notifyAll();
}
}
}
private IPrintSpooler getRemoteInstanceLazy() throws TimeoutException {
synchronized (mLock) {
if (mRemoteInstance != null) {
@@ -672,70 +593,5 @@ final class RemotePrintSpooler {
}
}
}
@Override
public void createPrinterDiscoverySession() {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
spooler.mCallbacks.createPrinterDiscoverySession();
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
@Override
public void destroyPrinterDiscoverySession() {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
spooler.mCallbacks.destroyPrinterDiscoverySession();
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
@Override
public void startPrinterDiscovery(List<PrinterId> priorityList) {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
spooler.mCallbacks.startPrinterDiscovery(priorityList);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
@Override
public void stopPrinterDiscovery() {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
spooler.mCallbacks.stopPrinterDiscovery();
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
@Override
public void requestPrinterUpdate(PrinterId printerId) {
RemotePrintSpooler spooler = mWeakSpooler.get();
if (spooler != null) {
final long identity = Binder.clearCallingIdentity();
try {
spooler.mCallbacks.requestPrinterUpdate(printerId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
}
}
}

View File

@@ -21,14 +21,26 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.print.IPrinterDiscoveryObserver;
import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintSpooler.PrintSpoolerCallbacks;
import java.util.ArrayList;
@@ -45,6 +57,10 @@ final class UserState implements PrintSpoolerCallbacks {
private static final String LOG_TAG = "UserState";
private static final boolean DEBUG = true && Build.IS_DEBUGGABLE;
private static final int MAX_ITEMS_PER_CALLBACK = 100;
private static final char COMPONENT_NAME_SEPARATOR = ':';
private final SimpleStringSplitter mStringColonSplitter =
@@ -70,6 +86,8 @@ final class UserState implements PrintSpoolerCallbacks {
private final RemotePrintSpooler mSpooler;
private PrinterDiscoverySessionMediator mPrinterDiscoverySession;
private boolean mDestroyed;
public UserState(Context context, int userId, Object lock) {
@@ -104,86 +122,135 @@ final class UserState implements PrintSpoolerCallbacks {
}
}
@Override
public void createPrinterDiscoverySession() {
final List<RemotePrintService> services;
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
if (mActiveServices.isEmpty()) {
return;
}
services = new ArrayList<RemotePrintService>(mActiveServices.values());
}
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.createPrinterDiscoverySession();
if (mPrinterDiscoverySession == null) {
// If we do not have a session, tell all service to create one.
mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
@Override
public void onDestroyed() {
mPrinterDiscoverySession = null;
}
};
// Add the observer to the brand new session.
mPrinterDiscoverySession.addObserverLocked(observer);
} else {
// If services have created session, just add the observer.
mPrinterDiscoverySession.addObserverLocked(observer);
}
}
}
@Override
public void destroyPrinterDiscoverySession() {
final List<RemotePrintService> services;
public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
// Already destroyed - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
// Remove this observer.
mPrinterDiscoverySession.removeObserverLocked(observer);
}
}
public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
if (mActiveServices.isEmpty()) {
return;
}
services = new ArrayList<RemotePrintService>(mActiveServices.values());
}
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.destroyPrinterDiscoverySession();
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
// Kick of discovery.
mPrinterDiscoverySession.startPrinterDiscoveryLocked(observer,
printerIds);
}
}
@Override
public void startPrinterDiscovery(List<PrinterId> printerIds) {
final List<RemotePrintService> services;
public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
if (mActiveServices.isEmpty()) {
return;
}
services = new ArrayList<RemotePrintService>(mActiveServices.values());
}
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.startPrinterDiscovery(printerIds);
}
}
@Override
public void stopPrinterDiscovery() {
final List<RemotePrintService> services;
synchronized (mLock) {
throwIfDestroyedLocked();
if (mActiveServices.isEmpty()) {
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
services = new ArrayList<RemotePrintService>(mActiveServices.values());
}
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.stopPrinterDiscovery();
// Kick of discovery.
mPrinterDiscoverySession.stopPrinterDiscoveryLocked(observer);
}
}
@Override
public void requestPrinterUpdate(PrinterId printerId) {
final RemotePrintService service;
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
if (mActiveServices.isEmpty()) {
return;
}
service = mActiveServices.get(printerId.getServiceName());
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
// Request an updated.
mPrinterDiscoverySession.requestPrinterUpdateLocked(printerId);
}
if (service != null) {
service.requestPrinterUpdate(printerId);
}
public void onPrintersAdded(List<PrinterInfo> printers) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
if (mActiveServices.isEmpty()) {
return;
}
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
// Request an updated.
mPrinterDiscoverySession.onPrintersAddedLocked(printers);
}
}
public void onPrintersRemoved(List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
if (mActiveServices.isEmpty()) {
return;
}
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
// Request an updated.
mPrinterDiscoverySession.onPrintersRemovedLocked(printerIds);
}
}
public void onPrintersUpdated(List<PrinterInfo> printers) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
if (mActiveServices.isEmpty()) {
return;
}
// No session - nothing to do.
if (mPrinterDiscoverySession == null) {
return;
}
// Request an updated.
mPrinterDiscoverySession.onPrintersUpdatedLocked(printers);
}
}
@@ -222,6 +289,10 @@ final class UserState implements PrintSpoolerCallbacks {
mActiveServices.clear();
mInstalledServices.clear();
mEnabledServices.clear();
if (mPrinterDiscoverySession != null) {
mPrinterDiscoverySession.destroyLocked();
mPrinterDiscoverySession = null;
}
mDestroyed = true;
}
@@ -302,13 +373,20 @@ final class UserState implements PrintSpoolerCallbacks {
resolveInfo.serviceInfo.name);
if (mEnabledServices.contains(serviceName)) {
if (!mActiveServices.containsKey(serviceName)) {
mActiveServices.put(serviceName, new RemotePrintService(
mContext, serviceName, mUserId, mSpooler));
RemotePrintService service = new RemotePrintService(
mContext, serviceName, mUserId, mSpooler, this);
mActiveServices.put(serviceName, service);
if (mPrinterDiscoverySession != null) {
mPrinterDiscoverySession.onServiceAddedLocked(service);
}
}
} else {
RemotePrintService service = mActiveServices.remove(serviceName);
if (service != null) {
service.destroy();
if (mPrinterDiscoverySession != null) {
mPrinterDiscoverySession.onServiceRemovedLocked(serviceName);
}
}
}
}
@@ -319,5 +397,496 @@ final class UserState implements PrintSpoolerCallbacks {
throw new IllegalStateException("Cannot interact with a destroyed instance.");
}
}
}
private class PrinterDiscoverySessionMediator {
private final ArrayMap<PrinterId, PrinterInfo> mPrinters =
new ArrayMap<PrinterId, PrinterInfo>();
private final RemoteCallbackList<IPrinterDiscoveryObserver> mDiscoveryObservers =
new RemoteCallbackList<IPrinterDiscoveryObserver>() {
@Override
public void onCallbackDied(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
stopPrinterDiscoveryLocked(observer);
removeObserverLocked(observer);
}
}
};
private final List<IBinder> mStartedPrinterDiscoveryTokens = new ArrayList<IBinder>();
private final Handler mHandler;
private boolean mIsDestroyed;
public PrinterDiscoverySessionMediator(Context context) {
mHandler = new SessionHandler(context.getMainLooper());
// Kick off the session creation.
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
mHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
.sendToTarget();
}
public void addObserverLocked(IPrinterDiscoveryObserver observer) {
// Add the observer.
mDiscoveryObservers.register(observer);
// Bring the added observer up to speed with the printers.
if (!mPrinters.isEmpty()) {
List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values());
SomeArgs args = SomeArgs.obtain();
args.arg1 = observer;
args.arg2 = printers;
mHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
args).sendToTarget();
}
}
public void removeObserverLocked(IPrinterDiscoveryObserver observer) {
// Remove the observer.
mDiscoveryObservers.unregister(observer);
// No one else observing - then kill it.
if (mDiscoveryObservers.getRegisteredCallbackCount() == 0) {
destroyLocked();
}
}
public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer,
List<PrinterId> priorityList) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not starting dicovery - session destroyed");
return;
}
// If printer discovery is ongoing and the start request has a list
// of printer to be checked, then we just request refreshing each of
// them rather making another start discovery request.
if (!mStartedPrinterDiscoveryTokens.isEmpty()
&& priorityList != null && !priorityList.isEmpty()) {
final int priorityIdCount = priorityList.size();
for (int i = 0; i < priorityIdCount; i++) {
requestPrinterUpdate(priorityList.get(i));
}
return;
}
// Remember we got a start request to match with an end.
mStartedPrinterDiscoveryTokens.add(observer.asBinder());
// The service are already performing discovery - nothing to do.
if (mStartedPrinterDiscoveryTokens.size() > 1) {
return;
}
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
SomeArgs args = SomeArgs.obtain();
args.arg1 = services;
args.arg2 = priorityList;
mHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
.sendToTarget();
}
public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not stopping dicovery - session destroyed");
return;
}
// This one did not make an active discovery request - nothing to do.
if (!mStartedPrinterDiscoveryTokens.remove(observer.asBinder())) {
return;
}
// There are other interested observers - do not stop discovery.
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
return;
}
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
mHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
.sendToTarget();
}
public void requestPrinterUpdateLocked(PrinterId printerId) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not updating pritner - session destroyed");
return;
}
RemotePrintService service = mActiveServices.get(printerId.getServiceName());
if (service != null) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = service;
args.arg2 = printerId;
mHandler.obtainMessage(SessionHandler
.MSG_REQUEST_PRINTER_UPDATE, args)
.sendToTarget();
}
}
public void onDestroyed() {
/* do nothing */
}
public void destroyLocked() {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not destroying - session destroyed");
return;
}
// Make sure discovery is stopped.
final int observerCount = mStartedPrinterDiscoveryTokens.size();
for (int i = 0; i < observerCount; i++) {
IBinder token = mStartedPrinterDiscoveryTokens.get(i);
stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token));
}
// Tell the services we are done.
List<RemotePrintService> services = new ArrayList<RemotePrintService>(
mActiveServices.values());
mHandler.obtainMessage(SessionHandler
.MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
.sendToTarget();
}
public void onPrintersAddedLocked(List<PrinterInfo> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "onPrintersAddedLocked()");
}
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not adding printers - session destroyed");
return;
}
List<PrinterInfo> addedPrinters = null;
final int addedPrinterCount = printers.size();
for (int i = 0; i < addedPrinterCount; i++) {
PrinterInfo printer = printers.get(i);
if (!mPrinters.containsKey(printer.getId())) {
mPrinters.put(printer.getId(), printer);
if (addedPrinters == null) {
addedPrinters = new ArrayList<PrinterInfo>();
}
addedPrinters.add(printer);
}
}
if (addedPrinters != null) {
mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
addedPrinters).sendToTarget();
}
}
public void onPrintersRemovedLocked(List<PrinterId> printerIds) {
if (DEBUG) {
Log.i(LOG_TAG, "onPrintersRemovedLocked()");
}
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not removing printers - session destroyed");
return;
}
List<PrinterId> removedPrinterIds = null;
final int removedPrinterCount = printerIds.size();
for (int i = 0; i < removedPrinterCount; i++) {
PrinterId removedPrinterId = printerIds.get(i);
if (mPrinters.remove(removedPrinterId) != null) {
if (removedPrinterIds == null) {
removedPrinterIds = new ArrayList<PrinterId>();
}
removedPrinterIds.add(removedPrinterId);
}
}
if (removedPrinterIds != null) {
mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinterIds).sendToTarget();
}
}
public void onPrintersUpdatedLocked(List<PrinterInfo> printers) {
if (DEBUG) {
Log.i(LOG_TAG, "onPrintersUpdatedLocked()");
}
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not updating printers - session destroyed");
return;
}
List<PrinterInfo> updatedPrinters = null;
final int updatedPrinterCount = printers.size();
for (int i = 0; i < updatedPrinterCount; i++) {
PrinterInfo updatedPrinter = printers.get(i);
if (mPrinters.containsKey(updatedPrinter.getId())) {
mPrinters.put(updatedPrinter.getId(), updatedPrinter);
if (updatedPrinters == null) {
updatedPrinters = new ArrayList<PrinterInfo>();
}
updatedPrinters.add(updatedPrinter);
}
}
if (updatedPrinters != null) {
mHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_UPDATED,
updatedPrinters).sendToTarget();
}
}
public void onServiceRemovedLocked(ComponentName serviceName) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not updating removed service - session destroyed");
return;
}
// No printers - nothing to do.
if (mPrinters.isEmpty()) {
return;
}
// Remove the printers for that service.
List<PrinterInfo> removedPrinters = null;
final int printerCount = mPrinters.size();
for (int i = 0; i < printerCount; i++) {
PrinterInfo printer = mPrinters.get(i);
if (printer.getId().getServiceName().equals(serviceName)) {
if (removedPrinters == null) {
removedPrinters = new ArrayList<PrinterInfo>();
}
removedPrinters.add(printer);
}
}
if (!removedPrinters.isEmpty()) {
mHandler.obtainMessage(
SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
removedPrinters).sendToTarget();
}
}
public void onServiceAddedLocked(RemotePrintService service) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not updating added service - session destroyed");
return;
}
// Tell the service to create a session.
mHandler.obtainMessage(
SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
service).sendToTarget();
// If there are some observers that started discovery - tell the service.
if (mDiscoveryObservers.getRegisteredCallbackCount() > 0) {
mHandler.obtainMessage(
SessionHandler.MSG_START_PRINTER_DISCOVERY,
service).sendToTarget();
}
}
private void handleDispatchPrintersAdded(List<PrinterInfo> addedPrinters) {
final int observerCount = mDiscoveryObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
try {
observer.onPrintersAdded(addedPrinters);
} catch (RemoteException re) {
Log.i(LOG_TAG, "Error dispatching added printers", re);
}
}
mDiscoveryObservers.finishBroadcast();
}
private void handleDispatchPrintersRemoved(List<PrinterId> removedPrinterIds) {
final int observerCount = mDiscoveryObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
try {
observer.onPrintersRemoved(removedPrinterIds);
} catch (RemoteException re) {
Log.i(LOG_TAG, "Error dispatching removed printers", re);
}
}
mDiscoveryObservers.finishBroadcast();
}
private void handleDispatchPrintersUpdated(List<PrinterInfo> updatedPrinters) {
final int observerCount = mDiscoveryObservers.beginBroadcast();
for (int i = 0; i < observerCount; i++) {
IPrinterDiscoveryObserver observer = mDiscoveryObservers.getBroadcastItem(i);
try {
observer.onPrintersUpdated(updatedPrinters);
} catch (RemoteException re) {
Log.i(LOG_TAG, "Error dispatching updated printers", re);
}
}
mDiscoveryObservers.finishBroadcast();
}
private void handleDispatchCreatePrinterDiscoverySession(
List<RemotePrintService> services) {
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.createPrinterDiscoverySession();
}
}
private void handleDispatchDestroyPrinterDiscoverySession(
List<RemotePrintService> services) {
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.destroyPrinterDiscoverySession();
}
onDestroyed();
}
private void handleDispatchStartPrinterDiscovery(
List<RemotePrintService> services, List<PrinterId> printerIds) {
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.startPrinterDiscovery(printerIds);
}
}
private void handleDispatchStopPrinterDiscovery(List<RemotePrintService> services) {
final int serviceCount = services.size();
for (int i = 0; i < serviceCount; i++) {
RemotePrintService service = services.get(i);
service.stopPrinterDiscovery();
}
}
private void handleRequestPrinterUpdate(RemotePrintService service,
PrinterId printerId) {
service.requestPrinterUpdate(printerId);
}
private void handlePrintersAdded(IPrinterDiscoveryObserver observer,
List<PrinterInfo> printers) {
try {
final int printerCount = printers.size();
if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
observer.onPrintersAdded(printers);
} else {
// Send the added printers in chunks avoiding the binder transaction limit.
final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
for (int i = 0; i < transactionCount; i++) {
final int start = i * MAX_ITEMS_PER_CALLBACK;
final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
List<PrinterInfo> subPrinters = printers.subList(start, end);
observer.onPrintersAdded(subPrinters);
}
}
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error sending added printers", re);
}
}
private void handlePrintersRemoved(IPrinterDiscoveryObserver observer,
List<PrinterId> printerIds) {
try {
final int printerCount = printerIds.size();
if (printerCount <= MAX_ITEMS_PER_CALLBACK) {
observer.onPrintersRemoved(printerIds);
} else {
// Send the added printers in chunks avoiding the binder transaction limit.
final int transactionCount = (printerCount / MAX_ITEMS_PER_CALLBACK) + 1;
for (int i = 0; i < transactionCount; i++) {
final int start = i * MAX_ITEMS_PER_CALLBACK;
final int end = Math.min(start + MAX_ITEMS_PER_CALLBACK, printerCount);
List<PrinterId> subPrinterIds = printerIds.subList(start, end);
observer.onPrintersRemoved(subPrinterIds);
}
}
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error sending added printers", re);
}
}
private final class SessionHandler extends Handler {
public static final int MSG_PRINTERS_ADDED = 1;
public static final int MSG_PRINTERS_REMOVED = 2;
public static final int MSG_DISPATCH_PRINTERS_ADDED = 3;
public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
public static final int MSG_DISPATCH_PRINTERS_UPDATED = 5;
public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 6;
public static final int MSG_START_PRINTER_DISCOVERY = 7;
public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 8;
public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 9;
public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 10;
public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 11;
public static final int MSG_REQUEST_PRINTER_UPDATE = 12;
SessionHandler(Looper looper) {
super(looper, null, false);
}
@Override
@SuppressWarnings("unchecked")
public void handleMessage(Message message) {
switch (message.what) {
case MSG_PRINTERS_ADDED: {
SomeArgs args = (SomeArgs) message.obj;
IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2;
args.recycle();
handlePrintersAdded(observer, addedPrinters);
} break;
case MSG_PRINTERS_REMOVED: {
SomeArgs args = (SomeArgs) message.obj;
IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2;
args.recycle();
handlePrintersRemoved(observer, removedPrinterIds);
}
case MSG_DISPATCH_PRINTERS_ADDED: {
List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj;
handleDispatchPrintersAdded(addedPrinters);
} break;
case MSG_DISPATCH_PRINTERS_REMOVED: {
List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj;
handleDispatchPrintersRemoved(removedPrinterIds);
} break;
case MSG_DISPATCH_PRINTERS_UPDATED: {
List<PrinterInfo> updatedPrinters = (List<PrinterInfo>) message.obj;
handleDispatchPrintersUpdated(updatedPrinters);
} break;
case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
RemotePrintService service = (RemotePrintService) message.obj;
service.createPrinterDiscoverySession();
} break;
case MSG_START_PRINTER_DISCOVERY: {
RemotePrintService service = (RemotePrintService) message.obj;
service.startPrinterDiscovery(null);
} break;
case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
handleDispatchCreatePrinterDiscoverySession(services);
} break;
case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: {
List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
handleDispatchDestroyPrinterDiscoverySession(services);
} break;
case MSG_DISPATCH_START_PRINTER_DISCOVERY: {
SomeArgs args = (SomeArgs) message.obj;
List<RemotePrintService> services = (List<RemotePrintService>) args.arg1;
List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
args.recycle();
handleDispatchStartPrinterDiscovery(services, printerIds);
} break;
case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: {
List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
handleDispatchStopPrinterDiscovery(services);
} break;
case MSG_REQUEST_PRINTER_UPDATE: {
SomeArgs args = (SomeArgs) message.obj;
RemotePrintService service = (RemotePrintService) args.arg1;
PrinterId printerId = (PrinterId) args.arg2;
args.recycle();
handleRequestPrinterUpdate(service, printerId);
} break;
}
}
}
}
}