diff options
-rw-r--r-- | Android.mk | 1 | ||||
-rw-r--r-- | CleanSpec.mk | 2 | ||||
-rw-r--r-- | core/java/android/print/IPrintManager.aidl | 7 | ||||
-rw-r--r-- | core/java/android/print/IPrintSpooler.aidl | 5 | ||||
-rw-r--r-- | core/java/android/print/PrintManager.java | 101 | ||||
-rw-r--r-- | packages/PrintSpooler/AndroidManifest.xml | 7 | ||||
-rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java | 160 | ||||
-rw-r--r-- | packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java | 223 | ||||
-rw-r--r-- | services/java/com/android/server/print/PrintManagerService.java | 28 | ||||
-rw-r--r-- | services/java/com/android/server/print/RemotePrintSpooler.java | 7 | ||||
-rw-r--r-- | services/java/com/android/server/print/UserState.java | 38 |
11 files changed, 333 insertions, 246 deletions
diff --git a/Android.mk b/Android.mk index 0957faeba4b3..166db4ee016b 100644 --- a/Android.mk +++ b/Android.mk @@ -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 \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 758273b78f7e..cfa8be9a13c7 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -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 # ************************************************ diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl index 3bd515b810df..8fa7ab90ebad 100644 --- a/core/java/android/print/IPrintManager.aidl +++ b/core/java/android/print/IPrintManager.aidl @@ -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); diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl index 5f06b834ade1..7b2cf253d56a 100644 --- a/core/java/android/print/IPrintSpooler.aidl +++ b/core/java/android/print/IPrintSpooler.aidl @@ -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, diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index 1cb4e8d6e651..1233da2183a7 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -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) { - return new PrintJob(printJob, this); + 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(); diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index 1e6954e40d40..7eea3e919a20 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -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 diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 2922dd1e9535..007d9c0a937f 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -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,14 +216,31 @@ public class PrintJobConfigActivity extends Activity { return; } - mController.initialize(); - mEditor.initialize(); + 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(); - mEditor.refreshCurrentPrinter(); + if (mSpoolerProvider.getSpooler() != null) { + mEditor.refreshCurrentPrinter(); + } } @Override @@ -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) { - return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF; - } - if (position == 1) { + if (position == 0) { + if (mFakePdfPrinter != null) { + return DEST_ADAPTER_ITEM_ID_SAVE_AS_PDF; + } else { + return DEST_ADAPTER_ITEM_ID_ALL_PRINTERS; + } + } 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 */ + } + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java index e1ddb4011fab..98d00a92d756 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintSpoolerService.java @@ -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; + } + } } diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java index b8e1b0404f3c..7538caf2f8cb 100644 --- a/services/java/com/android/server/print/PrintManagerService.java +++ b/services/java/com/android/server/print/PrintManagerService.java @@ -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); diff --git a/services/java/com/android/server/print/RemotePrintSpooler.java b/services/java/com/android/server/print/RemotePrintSpooler.java index 4866f5792c38..ffe9806a2418 100644 --- a/services/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/java/com/android/server/print/RemotePrintSpooler.java @@ -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) { diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index b6c7853c1f01..1b373edf5d54 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -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) { |