am 6f688e87: am 8f34715b: Merge "Refactor how the print dialog activity is started." into klp-dev

* commit '6f688e879a2523393e8e0da072e1f62cb456276f':
  Refactor how the print dialog activity is started.
This commit is contained in:
Svetoslav
2013-10-11 10:06:03 -07:00
committed by Android Git Automerger
11 changed files with 333 additions and 246 deletions

View File

@ -165,7 +165,6 @@ LOCAL_SRC_FILES += \
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/IPrintJobStateChangeListener.aidl \
core/java/android/print/IPrintManager.aidl \
core/java/android/print/IPrintSpooler.aidl \

View File

@ -183,6 +183,8 @@ $(call add-clean-step, rm -f $(PRODUCT_OUT)/system/media/video/*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/media/audio/effects/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/framework-res_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/print/IPrintClient.*)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************

View File

@ -16,9 +16,9 @@
package android.print;
import android.os.Bundle;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
import android.print.PrintJobId;
import android.print.IPrintJobStateChangeListener;
import android.print.PrinterId;
@ -34,9 +34,8 @@ import android.printservice.PrintServiceInfo;
interface IPrintManager {
List<PrintJobInfo> getPrintJobInfos(int appId, int userId);
PrintJobInfo getPrintJobInfo(in PrintJobId printJobId, int appId, int userId);
PrintJobInfo print(String printJobName, in IPrintClient client,
in IPrintDocumentAdapter printAdapter, in PrintAttributes attributes,
int appId, int userId);
Bundle print(String printJobName, in IPrintDocumentAdapter printAdapter,
in PrintAttributes attributes, String packageName, int appId, int userId);
void cancelPrintJob(in PrintJobId printJobId, int appId, int userId);
void restartPrintJob(in PrintJobId printJobId, int appId, int userId);

View File

@ -18,8 +18,6 @@ package android.print;
import android.content.ComponentName;
import android.os.ParcelFileDescriptor;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintClient;
import android.print.IPrintSpoolerClient;
import android.print.IPrintSpoolerCallbacks;
import android.print.PrinterInfo;
@ -40,8 +38,7 @@ oneway interface IPrintSpooler {
int state, int appId, int sequence);
void getPrintJobInfo(in PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence);
void createPrintJob(in PrintJobInfo printJob, in IPrintClient client,
in IPrintDocumentAdapter printAdapter);
void createPrintJob(in PrintJobInfo printJob);
void setPrintJobState(in PrintJobId printJobId, int status, String stateReason,
IPrintSpoolerCallbacks callback, int sequence);
void setPrintJobTag(in PrintJobId printJobId, String tag, IPrintSpoolerCallbacks callback,

View File

@ -60,8 +60,47 @@ public final class PrintManager {
private static final boolean DEBUG = false;
private static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 1;
private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 2;
private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
/**
* The action for launching the print dialog activity.
*
* @hide
*/
public static final String ACTION_PRINT_DIALOG = "android.print.PRINT_DIALOG";
/**
* Extra with the intent for starting the print dialog.
* <p>
* <strong>Type:</strong> {@link android.content.IntentSender}
* </p>
*
* @hide
*/
public static final String EXTRA_PRINT_DIALOG_INTENT =
"android.print.intent.extra.EXTRA_PRINT_DIALOG_INTENT";
/**
* Extra with a print job.
* <p>
* <strong>Type:</strong> {@link android.print.PrintJobInfo}
* </p>
*
* @hide
*/
public static final String EXTRA_PRINT_JOB =
"android.print.intent.extra.EXTRA_PRINT_JOB";
/**
* Extra with the print document adapter to be printed.
* <p>
* <strong>Type:</strong> {@link android.print.IPrintDocumentAdapter}
* </p>
*
* @hide
*/
public static final String EXTRA_PRINT_DOCUMENT_ADAPTER =
"android.print.intent.extra.EXTRA_PRINT_DOCUMENT_ADAPTER";
/** @hide */
public static final int APP_ID_ANY = -2;
@ -74,8 +113,6 @@ public final class PrintManager {
private final int mAppId;
private final PrintClient mPrintClient;
private final Handler mHandler;
private Map<PrintJobStateChangeListener, PrintJobStateChangeListenerWrapper> mPrintJobStateChangeListeners;
@ -103,24 +140,10 @@ public final class PrintManager {
mService = service;
mUserId = userId;
mAppId = appId;
mPrintClient = new PrintClient(this);
mHandler = new Handler(context.getMainLooper(), null, false) {
@Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_START_PRINT_JOB_CONFIG_ACTIVITY: {
SomeArgs args = (SomeArgs) message.obj;
Context context = (Context) args.arg1;
IntentSender intent = (IntentSender) args.arg2;
args.recycle();
try {
context.startIntentSender(intent, null, 0, 0, 0);
} catch (SendIntentException sie) {
Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
}
}
break;
case MSG_NOTIFY_PRINT_JOB_STATE_CHANGED: {
SomeArgs args = (SomeArgs) message.obj;
PrintJobStateChangeListener listener =
@ -128,8 +151,7 @@ public final class PrintManager {
PrintJobId printJobId = (PrintJobId) args.arg2;
args.recycle();
listener.onPrintJobStateChanged(printJobId);
}
break;
} break;
}
}
};
@ -279,10 +301,20 @@ public final class PrintManager {
PrintDocumentAdapterDelegate delegate = new PrintDocumentAdapterDelegate(documentAdapter,
mContext.getMainLooper());
try {
PrintJobInfo printJob = mService.print(printJobName, mPrintClient, delegate,
attributes, mAppId, mUserId);
if (printJob != null) {
Bundle result = mService.print(printJobName, delegate,
attributes, mContext.getPackageName(), mAppId, mUserId);
if (result != null) {
PrintJobInfo printJob = result.getParcelable(EXTRA_PRINT_JOB);
IntentSender intent = result.getParcelable(EXTRA_PRINT_DIALOG_INTENT);
if (printJob == null || intent == null) {
return null;
}
try {
mContext.startIntentSender(intent, null, 0, 0, 0);
return new PrintJob(printJob, this);
} catch (SendIntentException sie) {
Log.e(LOG_TAG, "Couldn't start print job config activity.", sie);
}
}
} catch (RemoteException re) {
Log.e(LOG_TAG, "Error creating a print job", re);
@ -333,27 +365,6 @@ public final class PrintManager {
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
private static final class PrintClient extends IPrintClient.Stub {
private final WeakReference<PrintManager> mWeakPrintManager;
public PrintClient(PrintManager manager) {
mWeakPrintManager = new WeakReference<PrintManager>(manager);
}
@Override
public void startPrintJobConfigActivity(IntentSender intent) {
PrintManager manager = mWeakPrintManager.get();
if (manager != null) {
SomeArgs args = SomeArgs.obtain();
args.arg1 = manager.mContext;
args.arg2 = intent;
manager.mHandler.obtainMessage(MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
args).sendToTarget();
}
}
}
private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub {
private final Object mLock = new Object();

View File

@ -58,8 +58,13 @@
<activity
android:name=".PrintJobConfigActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
android:theme="@style/PrintJobConfigActivityTheme">
<intent-filter>
<action android:name="android.print.PRINT_DILAOG" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="printjob" android:pathPattern="*" />
</intent-filter>
</activity>
<activity

View File

@ -19,9 +19,11 @@ package com.android.printspooler;
import android.app.Activity;
import android.app.Dialog;
import android.app.LoaderManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.content.ServiceConnection;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.DataSetObserver;
@ -52,6 +54,7 @@ import android.print.PrintManager;
import android.print.PrinterCapabilitiesInfo;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.provider.DocumentsContract;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
@ -66,9 +69,9 @@ import android.view.View;
import android.view.View.MeasureSpec;
import android.view.View.OnAttachStateChangeListener;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewPropertyAnimator;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
@ -84,6 +87,8 @@ import android.widget.TextView;
import com.android.printspooler.MediaSizeUtils.MediaSizeComparator;
import libcore.io.IoUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@ -100,8 +105,6 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import libcore.io.IoUtils;
/**
* Activity for configuring a print job.
*/
@ -111,9 +114,6 @@ public class PrintJobConfigActivity extends Activity {
private static final boolean DEBUG = false;
public static final String EXTRA_PRINT_DOCUMENT_ADAPTER = "printDocumentAdapter";
public static final String EXTRA_PRINT_JOB = "printJob";
public static final String INTENT_EXTRA_PRINTER_ID = "INTENT_EXTRA_PRINTER_ID";
private static final int LOADER_ID_PRINTERS_LOADER = 1;
@ -177,6 +177,10 @@ public class PrintJobConfigActivity extends Activity {
private Dialog mGeneratingPrintJobDialog;
private PrintSpoolerProvider mSpoolerProvider;
private String mCallingPackageName;
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
@ -185,13 +189,13 @@ public class PrintJobConfigActivity extends Activity {
Bundle extras = getIntent().getExtras();
PrintJobInfo printJob = extras.getParcelable(EXTRA_PRINT_JOB);
PrintJobInfo printJob = extras.getParcelable(PrintManager.EXTRA_PRINT_JOB);
if (printJob == null) {
throw new IllegalArgumentException("printJob cannot be null");
}
mPrintJobId = printJob.getId();
mIPrintDocumentAdapter = extras.getBinder(EXTRA_PRINT_DOCUMENT_ADAPTER);
mIPrintDocumentAdapter = extras.getBinder(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER);
if (mIPrintDocumentAdapter == null) {
throw new IllegalArgumentException("PrintDocumentAdapter cannot be null");
}
@ -201,13 +205,9 @@ public class PrintJobConfigActivity extends Activity {
mCurrPrintAttributes.copyFrom(attributes);
}
setContentView(R.layout.print_job_config_activity_container);
mCallingPackageName = extras.getString(DocumentsContract.EXTRA_PACKAGE_NAME);
mDocument = new Document();
mController = new PrintController(new RemotePrintDocumentAdapter(
IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
PrintSpoolerService.peekInstance().generateFileForPrintJob(mPrintJobId)));
mEditor = new Editor();
setContentView(R.layout.print_job_config_activity_container);
try {
mIPrintDocumentAdapter.linkToDeath(mDeathRecipient, 0);
@ -216,15 +216,32 @@ public class PrintJobConfigActivity extends Activity {
return;
}
mDocument = new Document();
mEditor = new Editor();
mSpoolerProvider = new PrintSpoolerProvider(this,
new Runnable() {
@Override
public void run() {
// We got the spooler so unleash the UI.
mController = new PrintController(new RemotePrintDocumentAdapter(
IPrintDocumentAdapter.Stub.asInterface(mIPrintDocumentAdapter),
mSpoolerProvider.getSpooler().generateFileForPrintJob(mPrintJobId)));
mController.initialize();
mEditor.initialize();
mEditor.postCreate();
}
});
}
@Override
public void onResume() {
super.onResume();
if (mSpoolerProvider.getSpooler() != null) {
mEditor.refreshCurrentPrinter();
}
}
@Override
protected void onDestroy() {
@ -235,10 +252,10 @@ public class PrintJobConfigActivity extends Activity {
mController.finish();
}
if (mEditor.isPrintConfirmed() && mController.isFinished()) {
PrintSpoolerService.peekInstance().setPrintJobState(mPrintJobId,
mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_QUEUED, null);
} else {
PrintSpoolerService.peekInstance().setPrintJobState(mPrintJobId,
mSpoolerProvider.getSpooler().setPrintJobState(mPrintJobId,
PrintJobInfo.STATE_CANCELED, null);
}
mIPrintDocumentAdapter.unlinkToDeath(mDeathRecipient, 0);
@ -246,6 +263,7 @@ public class PrintJobConfigActivity extends Activity {
mGeneratingPrintJobDialog.dismiss();
mGeneratingPrintJobDialog = null;
}
mSpoolerProvider.destroy();
super.onDestroy();
}
@ -367,7 +385,7 @@ public class PrintJobConfigActivity extends Activity {
// we handle writing as usual.
handleOnLayoutFinished(mDocument.info, false, mRequestCounter.get());
} else {
PrintSpoolerService.peekInstance().setPrintJobAttributesNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobAttributesNoPersistence(
mPrintJobId, mCurrPrintAttributes);
mMetadata.putBoolean(PrintDocumentAdapter.EXTRA_PRINT_PREVIEW,
@ -412,7 +430,7 @@ public class PrintJobConfigActivity extends Activity {
if (infoChanged) {
mDocument.info = info;
// Set the info.
PrintSpoolerService.peekInstance().setPrintJobPrintDocumentInfoNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobPrintDocumentInfoNoPersistence(
mPrintJobId, info);
}
@ -420,7 +438,7 @@ public class PrintJobConfigActivity extends Activity {
// drop the pages since we have to fetch them again.
if (infoChanged || layoutChanged) {
mDocument.pages = null;
PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(
mPrintJobId, null);
}
@ -499,12 +517,12 @@ public class PrintJobConfigActivity extends Activity {
mControllerState = CONTROLLER_STATE_WRITE_COMPLETED;
// Update the document size.
File file = PrintSpoolerService.peekInstance()
File file = mSpoolerProvider.getSpooler()
.generateFileForPrintJob(mPrintJobId);
mDocument.info.setDataSize(file.length());
// Update the print job with the updated info.
PrintSpoolerService.peekInstance().setPrintJobPrintDocumentInfoNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobPrintDocumentInfoNoPersistence(
mPrintJobId, mDocument.info);
// Update which pages we have fetched.
@ -528,12 +546,12 @@ public class PrintJobConfigActivity extends Activity {
if (Arrays.equals(writtenPages, requestedPages)) {
// We got a document with exactly the pages we wanted. Hence,
// the printer has to print all pages in the data.
PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
ALL_PAGES_ARRAY);
} else if (Arrays.equals(writtenPages, ALL_PAGES_ARRAY)) {
// We requested specific pages but got all of them. Hence,
// the printer has to print only the requested pages.
PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
requestedPages);
} else if (PageRangeUtils.contains(writtenPages, requestedPages)) {
// We requested specific pages and got more but not all pages.
@ -543,7 +561,7 @@ public class PrintJobConfigActivity extends Activity {
final int offset = -writtenPages[0].getStart();
PageRange[] offsetPages = Arrays.copyOf(requestedPages, requestedPages.length);
PageRangeUtils.offset(offsetPages, offset);
PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
offsetPages);
} else if (Arrays.equals(requestedPages, ALL_PAGES_ARRAY)
&& writtenPages.length == 1 && writtenPages[0].getStart() == 0
@ -551,7 +569,7 @@ public class PrintJobConfigActivity extends Activity {
// We requested all pages via the special constant and got all
// of them as an explicit enumeration. Hence, the printer has
// to print only the requested pages.
PrintSpoolerService.peekInstance().setPrintJobPagesNoPersistence(mPrintJobId,
mSpoolerProvider.getSpooler().setPrintJobPagesNoPersistence(mPrintJobId,
writtenPages);
} else {
// We did not get the pages we requested, then the application
@ -566,11 +584,12 @@ public class PrintJobConfigActivity extends Activity {
private void requestCreatePdfFileOrFinish() {
if (mEditor.isPrintingToPdf()) {
PrintJobInfo printJob = PrintSpoolerService.peekInstance()
PrintJobInfo printJob = mSpoolerProvider.getSpooler()
.getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY);
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.setType("application/pdf");
intent.putExtra(Intent.EXTRA_TITLE, printJob.getLabel());
intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, mCallingPackageName);
startActivityForResult(intent, ACTIVITY_REQUEST_CREATE_FILE);
} else {
PrintJobConfigActivity.this.finish();
@ -741,12 +760,12 @@ public class PrintJobConfigActivity extends Activity {
InputStream in = null;
OutputStream out = null;
try {
PrintJobInfo printJob = PrintSpoolerService.peekInstance()
PrintJobInfo printJob = mSpoolerProvider.getSpooler()
.getPrintJobInfo(mPrintJobId, PrintManager.APP_ID_ANY);
if (printJob == null) {
return null;
}
File file = PrintSpoolerService.peekInstance()
File file = mSpoolerProvider.getSpooler()
.generateFileForPrintJob(mPrintJobId);
in = new FileInputStream(file);
out = getContentResolver().openOutputStream(uri);
@ -789,21 +808,21 @@ public class PrintJobConfigActivity extends Activity {
private EditText mPageRangeEditText;
private Spinner mDestinationSpinner;
private final DestinationAdapter mDestinationSpinnerAdapter;
private DestinationAdapter mDestinationSpinnerAdapter;
private Spinner mMediaSizeSpinner;
private final ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
private ArrayAdapter<SpinnerItem<MediaSize>> mMediaSizeSpinnerAdapter;
private Spinner mColorModeSpinner;
private final ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
private ArrayAdapter<SpinnerItem<Integer>> mColorModeSpinnerAdapter;
private Spinner mOrientationSpinner;
private final ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
private ArrayAdapter<SpinnerItem<Integer>> mOrientationSpinnerAdapter;
private Spinner mRangeOptionsSpinner;
private final ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
private ArrayAdapter<SpinnerItem<Integer>> mRangeOptionsSpinnerAdapter;
private final SimpleStringSplitter mStringCommaSplitter =
private SimpleStringSplitter mStringCommaSplitter =
new SimpleStringSplitter(',');
private View mContentContainer;
@ -814,7 +833,7 @@ public class PrintJobConfigActivity extends Activity {
private PrinterInfo mCurrentPrinter;
private final MediaSizeComparator mMediaSizeComparator;
private MediaSizeComparator mMediaSizeComparator;
private final OnItemSelectedListener mOnItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@ -826,6 +845,11 @@ public class PrintJobConfigActivity extends Activity {
return;
}
if (position == AdapterView.INVALID_POSITION) {
updateUi();
return;
}
if (id == DEST_ADAPTER_ITEM_ID_ALL_PRINTERS) {
startSelectPrinterActivity();
return;
@ -836,7 +860,7 @@ public class PrintJobConfigActivity extends Activity {
mCurrentPrinter = (PrinterInfo) mDestinationSpinnerAdapter
.getItem(position);
PrintSpoolerService.peekInstance().setPrintJobPrinterNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobPrinterNoPersistence(
mPrintJobId, mCurrentPrinter);
if (mCurrentPrinter.getStatus() == PrinterInfo.STATUS_UNAVAILABLE) {
@ -1053,7 +1077,7 @@ public class PrintJobConfigActivity extends Activity {
}
mCopiesEditText.setError(null);
PrintSpoolerService.peekInstance().setPrintJobCopiesNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobCopiesNoPersistence(
mPrintJobId, copies);
updateUi();
@ -1145,6 +1169,10 @@ public class PrintJobConfigActivity extends Activity {
private boolean mFavoritePrinterSelected;
public Editor() {
showUi(UI_EDITING_PRINT_JOB, null);
}
public void postCreate() {
// Destination.
mMediaSizeComparator = new MediaSizeComparator(PrintJobConfigActivity.this);
mDestinationSpinnerAdapter = new DestinationAdapter();
@ -1621,7 +1649,7 @@ public class PrintJobConfigActivity extends Activity {
if (!TextUtils.equals(mCopiesEditText.getText(), MIN_COPIES_STRING)) {
mIgnoreNextCopiesChange = true;
}
PrintSpoolerService.peekInstance().setPrintJobCopiesNoPersistence(
mSpoolerProvider.getSpooler().setPrintJobCopiesNoPersistence(
mPrintJobId, MIN_COPIES);
// Destination.
@ -1629,7 +1657,7 @@ public class PrintJobConfigActivity extends Activity {
mDestinationSpinner.setDropDownWidth(ViewGroup.LayoutParams.MATCH_PARENT);
mDestinationSpinner.setAdapter(mDestinationSpinnerAdapter);
mDestinationSpinner.setOnItemSelectedListener(mOnItemSelectedListener);
if (mDestinationSpinnerAdapter.getCount() > 0 && mController.hasStarted()) {
if (mDestinationSpinnerAdapter.getCount() > 0) {
mIgnoreNextDestinationChange = true;
}
@ -2089,10 +2117,13 @@ public class PrintJobConfigActivity extends Activity {
@Override
public long getItemId(int position) {
if (mPrinters.isEmpty()) {
if (position == 0 && mFakePdfPrinter != null) {
if (position == 0) {
if (mFakePdfPrinter != null) {
return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF;
} else {
return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
}
if (position == 1) {
} else if (position == 1) {
return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS;
}
} else {
@ -2484,4 +2515,41 @@ public class PrintJobConfigActivity extends Activity {
}
}
}
private static final class PrintSpoolerProvider implements ServiceConnection {
private final Context mContext;
private final Runnable mCallback;
private PrintSpoolerService mSpooler;
public PrintSpoolerProvider(Context context, Runnable callback) {
mContext = context;
mCallback = callback;
Intent intent = new Intent(mContext, PrintSpoolerService.class);
mContext.bindService(intent, this, 0);
}
public PrintSpoolerService getSpooler() {
return mSpooler;
}
public void destroy() {
if (mSpooler != null) {
mContext.unbindService(this);
}
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mSpooler = ((PrintSpoolerService.PrintSpooler) service).getService();
if (mSpooler != null) {
mCallback.run();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
/* do noting - we are in the same process */
}
}
}

View File

@ -16,18 +16,14 @@
package com.android.printspooler;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentSender;
import android.os.AsyncTask;
import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintSpooler;
import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
@ -50,7 +46,6 @@ import android.util.Slog;
import android.util.Xml;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.FastXmlSerializer;
import libcore.io.IoUtils;
@ -132,110 +127,7 @@ public final class PrintSpoolerService extends Service {
@Override
public IBinder onBind(Intent intent) {
return new IPrintSpooler.Stub() {
@Override
public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
ComponentName componentName, int state, int appId, int sequence)
throws RemoteException {
List<PrintJobInfo> printJobs = null;
try {
printJobs = PrintSpoolerService.this.getPrintJobInfos(
componentName, state, appId);
} finally {
callback.onGetPrintJobInfosResult(printJobs, sequence);
}
}
@Override
public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
PrintJobInfo printJob = null;
try {
printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId);
} finally {
callback.onGetPrintJobInfoResult(printJob, sequence);
}
}
@SuppressWarnings("deprecation")
@Override
public void createPrintJob(PrintJobInfo printJob, IPrintClient client,
IPrintDocumentAdapter printAdapter) throws RemoteException {
PrintSpoolerService.this.createPrintJob(printJob);
Intent intent = new Intent(printJob.getId().flattenToString());
intent.setClass(PrintSpoolerService.this, PrintJobConfigActivity.class);
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_DOCUMENT_ADAPTER,
printAdapter.asBinder());
intent.putExtra(PrintJobConfigActivity.EXTRA_PRINT_JOB, printJob);
IntentSender sender = PendingIntent.getActivity(
PrintSpoolerService.this, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob);
mHandlerCaller.executeOrSendMessage(message);
message = mHandlerCaller.obtainMessageOO(
HandlerCallerCallback.MSG_START_PRINT_JOB_CONFIG_ACTIVITY,
client, sender);
mHandlerCaller.executeOrSendMessage(message);
printJob.setCreationTime(System.currentTimeMillis());
}
@Override
public void setPrintJobState(PrintJobId printJobId, int state, String error,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
success = PrintSpoolerService.this.setPrintJobState(
printJobId, state, error);
} finally {
callback.onSetPrintJobStateResult(success, sequece);
}
}
@Override
public void setPrintJobTag(PrintJobId printJobId, String tag,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag);
} finally {
callback.onSetPrintJobTagResult(success, sequece);
}
}
@Override
public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
PrintSpoolerService.this.writePrintJobData(fd, printJobId);
}
@Override
public void setClient(IPrintSpoolerClient client) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_SET_CLIENT, client);
mHandlerCaller.executeOrSendMessage(message);
}
@Override
public void removeObsoletePrintJobs() {
PrintSpoolerService.this.removeObsoletePrintJobs();
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
PrintSpoolerService.this.dump(fd, writer, args);
}
@Override
public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling);
}
};
return new PrintSpooler();
}
@Override
@ -286,12 +178,11 @@ public final class PrintSpoolerService extends Service {
private final class HandlerCallerCallback implements HandlerCaller.Callback {
public static final int MSG_SET_CLIENT = 1;
public static final int MSG_START_PRINT_JOB_CONFIG_ACTIVITY = 2;
public static final int MSG_ON_PRINT_JOB_QUEUED = 3;
public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 4;
public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 5;
public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 6;
public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 7;
public static final int MSG_ON_PRINT_JOB_QUEUED = 2;
public static final int MSG_ON_ALL_PRINT_JOBS_FOR_SERIVICE_HANDLED = 3;
public static final int MSG_ON_ALL_PRINT_JOBS_HANDLED = 4;
public static final int MSG_CHECK_ALL_PRINTJOBS_HANDLED = 5;
public static final int MSG_ON_PRINT_JOB_STATE_CHANGED = 6;
@Override
public void executeMessage(Message message) {
@ -308,18 +199,6 @@ public final class PrintSpoolerService extends Service {
}
} break;
case MSG_START_PRINT_JOB_CONFIG_ACTIVITY: {
SomeArgs args = (SomeArgs) message.obj;
IPrintClient client = (IPrintClient) args.arg1;
IntentSender sender = (IntentSender) args.arg2;
args.recycle();
try {
client.startPrintJobConfigActivity(sender);
} catch (RemoteException re) {
Slog.i(LOG_TAG, "Error starting print job config activity!", re);
}
} break;
case MSG_ON_PRINT_JOB_QUEUED: {
PrintJobInfo printJob = (PrintJobInfo) message.obj;
if (mClient != null) {
@ -426,6 +305,11 @@ public final class PrintSpoolerService extends Service {
synchronized (mLock) {
addPrintJobLocked(printJob);
setPrintJobState(printJob.getId(), PrintJobInfo.STATE_CREATED, null);
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
printJob);
mHandlerCaller.executeOrSendMessage(message);
}
}
@ -1277,4 +1161,89 @@ public final class PrintSpoolerService extends Service {
return true;
}
}
final class PrintSpooler extends IPrintSpooler.Stub {
@Override
public void getPrintJobInfos(IPrintSpoolerCallbacks callback,
ComponentName componentName, int state, int appId, int sequence)
throws RemoteException {
List<PrintJobInfo> printJobs = null;
try {
printJobs = PrintSpoolerService.this.getPrintJobInfos(
componentName, state, appId);
} finally {
callback.onGetPrintJobInfosResult(printJobs, sequence);
}
}
@Override
public void getPrintJobInfo(PrintJobId printJobId, IPrintSpoolerCallbacks callback,
int appId, int sequence) throws RemoteException {
PrintJobInfo printJob = null;
try {
printJob = PrintSpoolerService.this.getPrintJobInfo(printJobId, appId);
} finally {
callback.onGetPrintJobInfoResult(printJob, sequence);
}
}
@Override
public void createPrintJob(PrintJobInfo printJob) {
PrintSpoolerService.this.createPrintJob(printJob);
}
@Override
public void setPrintJobState(PrintJobId printJobId, int state, String error,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
success = PrintSpoolerService.this.setPrintJobState(
printJobId, state, error);
} finally {
callback.onSetPrintJobStateResult(success, sequece);
}
}
@Override
public void setPrintJobTag(PrintJobId printJobId, String tag,
IPrintSpoolerCallbacks callback, int sequece) throws RemoteException {
boolean success = false;
try {
success = PrintSpoolerService.this.setPrintJobTag(printJobId, tag);
} finally {
callback.onSetPrintJobTagResult(success, sequece);
}
}
@Override
public void writePrintJobData(ParcelFileDescriptor fd, PrintJobId printJobId) {
PrintSpoolerService.this.writePrintJobData(fd, printJobId);
}
@Override
public void setClient(IPrintSpoolerClient client) {
Message message = mHandlerCaller.obtainMessageO(
HandlerCallerCallback.MSG_SET_CLIENT, client);
mHandlerCaller.executeOrSendMessage(message);
}
@Override
public void removeObsoletePrintJobs() {
PrintSpoolerService.this.removeObsoletePrintJobs();
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
PrintSpoolerService.this.dump(fd, writer, args);
}
@Override
public void setPrintJobCancelling(PrintJobId printJobId, boolean cancelling) {
PrintSpoolerService.this.setPrintJobCancelling(printJobId, cancelling);
}
public PrintSpoolerService getService() {
return PrintSpoolerService.this;
}
}
}

View File

@ -31,10 +31,10 @@ import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintManager;
@ -45,6 +45,7 @@ import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.SparseArray;
import com.android.internal.R;
@ -96,19 +97,19 @@ public final class PrintManagerService extends IPrintManager.Stub {
}
@Override
public PrintJobInfo print(String printJobName, final IPrintClient client,
final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
int appId, int userId) {
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId, int userId) {
final int resolvedAppId = resolveCallingAppEnforcingPermissions(appId);
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
String resolvedPackageName = resolveCallingPackageNameEnforcingSecurity(packageName);
final UserState userState;
synchronized (mLock) {
userState = getOrCreateUserStateLocked(resolvedUserId);
}
final long identity = Binder.clearCallingIdentity();
try {
return userState.print(printJobName, client, documentAdapter,
attributes, resolvedAppId);
return userState.print(printJobName, adapter, attributes,
resolvedPackageName, resolvedAppId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@ -605,6 +606,21 @@ public final class PrintManagerService extends IPrintManager.Stub {
+ "UserHandle.USER_CURRENT or UserHandle.USER_CURRENT_OR_SELF.");
}
private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
if (TextUtils.isEmpty(packageName)) {
return null;
}
String[] packages = mContext.getPackageManager().getPackagesForUid(
Binder.getCallingUid());
final int packageCount = packages.length;
for (int i = 0; i < packageCount; i++) {
if (packageName.equals(packages[i])) {
return packageName;
}
}
return null;
}
private void showEnableInstalledPrintServiceNotification(ComponentName component,
String label) {
Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS);

View File

@ -26,8 +26,6 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintSpooler;
import android.print.IPrintSpoolerCallbacks;
import android.print.IPrintSpoolerClient;
@ -130,15 +128,14 @@ final class RemotePrintSpooler {
return null;
}
public final void createPrintJob(PrintJobInfo printJob, IPrintClient client,
IPrintDocumentAdapter documentAdapter) {
public final void createPrintJob(PrintJobInfo printJob) {
throwIfCalledOnMainThread();
synchronized (mLock) {
throwIfDestroyedLocked();
mCanUnbind = false;
}
try {
getRemoteInstanceLazy().createPrintJob(printJob, client, documentAdapter);
getRemoteInstanceLazy().createPrintJob(printJob);
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Error creating print job.", re);
} catch (TimeoutException te) {

View File

@ -16,16 +16,20 @@
package com.android.server.print;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
@ -33,7 +37,6 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.print.IPrintClient;
import android.print.IPrintDocumentAdapter;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrinterDiscoveryObserver;
@ -44,6 +47,7 @@ import android.print.PrintManager;
import android.print.PrinterId;
import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.provider.DocumentsContract;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
@ -158,9 +162,9 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
mSpooler.removeObsoletePrintJobs();
}
public PrintJobInfo print(String printJobName, final IPrintClient client,
final IPrintDocumentAdapter documentAdapter, PrintAttributes attributes,
int appId) {
@SuppressWarnings("deprecation")
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId) {
// Create print job place holder.
final PrintJobInfo printJob = new PrintJobInfo();
printJob.setId(new PrintJobId());
@ -169,9 +173,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
printJob.setAttributes(attributes);
printJob.setState(PrintJobInfo.STATE_CREATED);
printJob.setCopies(1);
printJob.setCreationTime(System.currentTimeMillis());
// Track this job so we can forget it when the creator dies.
if (!mPrintJobForAppCache.onPrintJobCreated(client.asBinder(), appId,
if (!mPrintJobForAppCache.onPrintJobCreated(adapter.asBinder(), appId,
printJob)) {
// Not adding a print job means the client is dead - done.
return null;
@ -181,12 +186,31 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
mSpooler.createPrintJob(printJob, client, documentAdapter);
mSpooler.createPrintJob(printJob);
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
return printJob;
final long identity = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(PrintManager.ACTION_PRINT_DIALOG);
intent.setData(Uri.fromParts("printjob", printJob.getId().flattenToString(), null));
intent.putExtra(PrintManager.EXTRA_PRINT_DOCUMENT_ADAPTER, adapter.asBinder());
intent.putExtra(PrintManager.EXTRA_PRINT_JOB, printJob);
intent.putExtra(DocumentsContract.EXTRA_PACKAGE_NAME, packageName);
IntentSender intentSender = PendingIntent.getActivity(
mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT).getIntentSender();
Bundle result = new Bundle();
result.putParcelable(PrintManager.EXTRA_PRINT_JOB, printJob);
result.putParcelable(PrintManager.EXTRA_PRINT_DIALOG_INTENT, intentSender);
return result;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
public List<PrintJobInfo> getPrintJobInfos(int appId) {