diff options
| author | 2013-10-10 13:36:23 -0700 | |
|---|---|---|
| committer | 2013-10-11 09:11:24 -0700 | |
| commit | 7bfbbcb04bf4ba8f3069b2df136f708c9849bacf (patch) | |
| tree | da453e5f618eacb7cf63de3ef1344507feeecb0a | |
| parent | 1db8cf12a985425a73d24875d9d308c14c0b4359 (diff) | |
Refactor how the print dialog activity is started.
1. Before the print job activity was started asyncronously with
respect to the print call on to the print manager. This was
creating a situation where the starting activity may finish
before the print dialog appears which may lead to an orphaned
print document adapter with no data to print (as the UI is
is gone), or strange behaviors where the print dialog starts
on as a separate task.
To address this the pending intent for starting the print
dialog is not started by the print spooler since we cannot
call into it synchronously as we have to start its process
and bind to the spooler service which leads to jankyness in
the client app. Now the pending intent is created by the
print manager service in the synchronous print call so
from an app's perspective calling print starts the activity.
The side effect of this design is that the print dialog
activity may start before the system is bound to the spooler
service. In such a case the print activity cannot start
poking the print spooler state as the system registers
callback to observe the spooler state. To address this
the print spooler activity disables the UI and also binds
to the spooler service which happenes immediately after it
is started. As soon as the print dialog binds to the
service it starts the UI.
2. Fixed an bug in the printer adapter of the print dialog that
was leading to a crash if the only item in the adater is the
all pritners option and it is selected.
3. Piping the package name that started the printing so we can
pass it to the storage UI as a hint to open the last location
the app used.
bug:11127269
Change-Id: Ia93820bdae0b0e7600a0930b1f10d9708bd86b68
| -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) { |