diff options
10 files changed, 298 insertions, 101 deletions
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl index fb6bb2e..d2ae5e6 100644 --- a/core/java/android/print/IPrintManager.aidl +++ b/core/java/android/print/IPrintManager.aidl @@ -22,6 +22,7 @@ import android.print.IPrintClient; import android.print.PrinterId; import android.print.PrintJobInfo; import android.print.PrintAttributes; +import android.printservice.PrintServiceInfo; /** * Interface for communication with the core print manager service. @@ -37,6 +38,8 @@ interface IPrintManager { void cancelPrintJob(int printJobId, int appId, int userId); void restartPrintJob(int printJobId, int appId, int userId); + List<PrintServiceInfo> getEnabledPrintServices(int userId); + void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId); void startPrinterDiscovery(in IPrinterDiscoveryObserver observer, in List<PrinterId> priorityList, int userId); diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java index 6e32c05..10cc771 100644 --- a/core/java/android/print/PrintManager.java +++ b/core/java/android/print/PrintManager.java @@ -28,6 +28,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.print.PrintDocumentAdapter.LayoutResultCallback; import android.print.PrintDocumentAdapter.WriteResultCallback; +import android.printservice.PrintServiceInfo; import android.text.TextUtils; import android.util.Log; @@ -204,6 +205,25 @@ public final class PrintManager { } /** + * Gets the list of enabled print services. + * + * @return The enabled service list or an empty list. + * + * @hide + */ + public List<PrintServiceInfo> getEnabledPrintServices() { + try { + List<PrintServiceInfo> enabledServices = mService.getEnabledPrintServices(mUserId); + if (enabledServices != null) { + return enabledServices; + } + } catch (RemoteException re) { + Log.e(LOG_TAG, "Error getting the enalbed print services", re); + } + return Collections.emptyList(); + } + + /** * @hide */ public PrinterDiscoverySession createPrinterDiscoverySession() { diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java index 012e76a..e5ebf77 100644 --- a/core/java/android/printservice/PrintService.java +++ b/core/java/android/printservice/PrintService.java @@ -178,6 +178,14 @@ public abstract class PrintService extends Service { * For detailed configuration options that can be specified via the meta-data * refer to {@link android.R.styleable#PrintService android.R.styleable.PrintService}. * </p> + * <p> + * If you declare a settings or add a printers activity, they have to be exported, + * by setting the {@link android.R.attr#exported} activity attribute to <code>true + * </code>. Also in case you want only the system to be able to start any of these + * activities you can specify that they request the android.permission + * .START_PRINT_SERVICE_CONFIG_ACTIVITY permission by setting the + * {@link android.R.attr#permission} activity attribute. + * </p> */ public static final String SERVICE_META_DATA = "android.printservice"; diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml index 83ec1ad..9319025 100644 --- a/packages/PrintSpooler/AndroidManifest.xml +++ b/packages/PrintSpooler/AndroidManifest.xml @@ -22,17 +22,24 @@ android:versionCode="1"> <!-- Allows an application to call APIs that give it access to all print jobs - on the device. Usually an app can access only the print jobs it created. - --> + on the device. Usually an app can access only the print jobs it created. --> <permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS" android:label="@string/permlab_accessAllPrintJobs" android:description="@string/permdesc_accessAllPrintJobs" android:protectionLevel="signature" /> + <!-- May be required by the settings and add printer activities of a + print service if the developer wants only trusted system code to + be able to launch these activities. --> + <permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY" + android:label="@string/permlab_startPrintServiceConfigActivity" + android:description="@string/permdesc_startPrintServiceConfigActivity" + android:protectionLevel="signature" /> + <uses-permission android:name="com.android.printspooler.permission.ACCESS_ALL_PRINT_JOBS"/> - <uses-permission android:name="android.permission.ACCESS_ALL_PRINT_JOBS"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> + <uses-permission android:name="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"/> <uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18"/> diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 235a7a1..21a4867 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -145,4 +145,12 @@ <string name="permdesc_accessAllPrintJobs">Allows the holder to access print jobs created by another app. Should never be needed for normal apps.</string> + <!-- Title of an application permission, listed so the user can choose whether they want + to allow the application to do this. --> + <string name="permlab_startPrintServiceConfigActivity">start print service configuration activities</string> + <!-- Description of an application permission, listed so the user can choose whether they + want to allow the application to do this. --> + <string name="permdesc_startPrintServiceConfigActivity">Allows the holder to start the + configuration activities of a print service. Should never be needed for normal apps.</string> + </resources> diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java index 5c3d700..14f60f1 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java @@ -62,9 +62,11 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.View.MeasureSpec; +import android.view.View.OnAttachStateChangeListener; import android.view.View.OnClickListener; import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; @@ -1371,7 +1373,8 @@ public class PrintJobConfigActivity extends Activity { null, false); // First animation - fade out the old content. - hidingView.animate().alpha(0.0f).withLayer().withEndAction(new Runnable() { + AutoCancellingAnimator.animate(hidingView).alpha(0.0f) + .withLayer().withEndAction(new Runnable() { @Override public void run() { hidingView.setVisibility(View.INVISIBLE); @@ -1390,8 +1393,8 @@ public class PrintJobConfigActivity extends Activity { / (float) contentContainer.getHeight(); // Second animation - resize the container. - contentContainer.animate().scaleY(scaleY).withLayer().withEndAction( - new Runnable() { + AutoCancellingAnimator.animate(contentContainer).scaleY(scaleY).withLayer() + .withEndAction(new Runnable() { @Override public void run() { // Swap the old and the new content. @@ -1400,8 +1403,8 @@ public class PrintJobConfigActivity extends Activity { contentContainer.addView(showingView); // Third animation - show the new content. - showingView.animate().withLayer().alpha(1.0f).withEndAction( - new Runnable() { + AutoCancellingAnimator.animate(showingView).withLayer().alpha(1.0f) + .withEndAction(new Runnable() { @Override public void run() { postAnimateCommand.run(); @@ -2212,4 +2215,67 @@ public class PrintJobConfigActivity extends Activity { } } } + + private static final class AutoCancellingAnimator + implements OnAttachStateChangeListener, Runnable { + + private ViewPropertyAnimator mAnimator; + + private boolean mCancelled; + private Runnable mEndCallback; + + public static AutoCancellingAnimator animate(View view) { + ViewPropertyAnimator animator = view.animate(); + AutoCancellingAnimator cancellingWrapper = + new AutoCancellingAnimator(animator); + view.addOnAttachStateChangeListener(cancellingWrapper); + return cancellingWrapper; + } + + private AutoCancellingAnimator(ViewPropertyAnimator animator) { + mAnimator = animator; + } + + public AutoCancellingAnimator alpha(float alpha) { + mAnimator = mAnimator.alpha(alpha); + return this; + } + + public void cancel() { + mAnimator.cancel(); + } + + public AutoCancellingAnimator withLayer() { + mAnimator = mAnimator.withLayer(); + return this; + } + + public AutoCancellingAnimator withEndAction(Runnable callback) { + mEndCallback = callback; + mAnimator = mAnimator.withEndAction(this); + return this; + } + + public AutoCancellingAnimator scaleY(float scale) { + mAnimator = mAnimator.scaleY(scale); + return this; + } + + @Override + public void onViewAttachedToWindow(View v) { + /* do nothing */ + } + + @Override + public void onViewDetachedFromWindow(View v) { + cancel(); + } + + @Override + public void run() { + if (!mCancelled) { + mEndCallback.run(); + } + } + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java index 9ca3a86..c397c40 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java +++ b/packages/PrintSpooler/src/com/android/printspooler/SelectPrinterFragment.java @@ -24,20 +24,26 @@ import android.app.Fragment; import android.app.FragmentTransaction; import android.app.ListFragment; import android.app.LoaderManager; +import android.content.ActivityNotFoundException; import android.content.ComponentName; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.Loader; +import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.net.Uri; import android.os.Bundle; +import android.print.PrintManager; import android.print.PrinterId; import android.print.PrinterInfo; import android.printservice.PrintServiceInfo; import android.text.TextUtils; +import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -59,6 +65,8 @@ import java.util.List; */ public final class SelectPrinterFragment extends ListFragment { + private static final String LOG_TAG = "SelectPrinterFragment"; + private static final int LOADER_ID_PRINTERS_LOADER = 1; private static final String FRAGMRNT_TAG_ADD_PRINTER_DIALOG = @@ -142,40 +150,45 @@ public final class SelectPrinterFragment extends ListFragment { private void updateAddPrintersAdapter() { mAddPrinterServices.clear(); - // Get all print services. - List<ResolveInfo> resolveInfos = getActivity().getPackageManager().queryIntentServices( - new Intent(android.printservice.PrintService.SERVICE_INTERFACE), - PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); + // Get all enabled print services. + PrintManager printManager = (PrintManager) getActivity() + .getSystemService(Context.PRINT_SERVICE); + List<PrintServiceInfo> enabledServices = printManager.getEnabledPrintServices(); - // No print services - done. - if (resolveInfos.isEmpty()) { + // No enabled print services - done. + if (enabledServices.isEmpty()) { return; } // Find the services with valid add printers activities. - final int resolveInfoCount = resolveInfos.size(); - for (int i = 0; i < resolveInfoCount; i++) { - ResolveInfo resolveInfo = resolveInfos.get(i); - - PrintServiceInfo printServiceInfo = PrintServiceInfo.create( - resolveInfo, getActivity()); - String addPrintersActivity = printServiceInfo.getAddPrintersActivityName(); + final int enabledServiceCount = enabledServices.size(); + for (int i = 0; i < enabledServiceCount; i++) { + PrintServiceInfo enabledService = enabledServices.get(i); // No add printers activity declared - done. - if (TextUtils.isEmpty(addPrintersActivity)) { + if (TextUtils.isEmpty(enabledService.getAddPrintersActivityName())) { continue; } + ServiceInfo serviceInfo = enabledService.getResolveInfo().serviceInfo; ComponentName addPrintersComponentName = new ComponentName( - resolveInfo.serviceInfo.packageName, - addPrintersActivity); - Intent addPritnersIntent = new Intent(Intent.ACTION_MAIN) + serviceInfo.packageName, enabledService.getAddPrintersActivityName()); + Intent addPritnersIntent = new Intent() .setComponent(addPrintersComponentName); // The add printers activity is valid - add it. - if (!getActivity().getPackageManager().queryIntentActivities( - addPritnersIntent, 0).isEmpty()) { - mAddPrinterServices.add(printServiceInfo); + PackageManager pm = getActivity().getPackageManager(); + List<ResolveInfo> resolvedActivities = pm.queryIntentActivities(addPritnersIntent, 0); + if (!resolvedActivities.isEmpty()) { + // The activity is a component name, therefore it is one or none. + ActivityInfo activityInfo = resolvedActivities.get(0).activityInfo; + if (activityInfo.exported + && (activityInfo.permission == null + || pm.checkPermission(activityInfo.permission, + getActivity().getPackageName()) + == PackageManager.PERMISSION_GRANTED)) { + mAddPrinterServices.add(enabledService); + } } } } @@ -228,7 +241,11 @@ public final class SelectPrinterFragment extends ListFragment { printService.getAddPrintersActivityName()); Intent intent = new Intent(Intent.ACTION_MAIN); intent.setComponent(componentName); - startActivity(intent); + try { + startActivity(intent); + } catch (ActivityNotFoundException anfe) { + Log.w(LOG_TAG, "Couldn't start settings activity", anfe); + } } }); @@ -238,7 +255,11 @@ public final class SelectPrinterFragment extends ListFragment { builder.setPositiveButton(R.string.search_play_store, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int whichButton) { - startActivity(marketIntent); + try { + startActivity(marketIntent); + } catch (ActivityNotFoundException anfe) { + Log.w(LOG_TAG, "Couldn't start add printer activity", anfe); + } } }); } diff --git a/services/java/com/android/server/print/PrintManagerService.java b/services/java/com/android/server/print/PrintManagerService.java index 926f822..c33bfb7 100644 --- a/services/java/com/android/server/print/PrintManagerService.java +++ b/services/java/com/android/server/print/PrintManagerService.java @@ -35,6 +35,7 @@ import android.print.IPrinterDiscoveryObserver; import android.print.PrintAttributes; import android.print.PrintJobInfo; import android.print.PrinterId; +import android.printservice.PrintServiceInfo; import android.provider.Settings; import android.util.SparseArray; @@ -192,6 +193,22 @@ public final class PrintManagerService extends IPrintManager.Stub { } } + + @Override + public List<PrintServiceInfo> getEnabledPrintServices(int userId) { + final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId); + final UserState userState; + synchronized (mLock) { + userState = getOrCreateUserStateLocked(resolvedUserId); + } + final long identity = Binder.clearCallingIdentity(); + try { + return userState.getEnabledPrintServices(); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer, int userId) { diff --git a/services/java/com/android/server/print/RemotePrintService.java b/services/java/com/android/server/print/RemotePrintService.java index f15c760..8869cbe 100644 --- a/services/java/com/android/server/print/RemotePrintService.java +++ b/services/java/com/android/server/print/RemotePrintService.java @@ -83,6 +83,8 @@ final class RemotePrintService implements DeathRecipient { private boolean mHasPrinterDiscoverySession; + private boolean mServiceDead; + private List<PrinterId> mDiscoveryPriorityList; private List<PrinterId> mTrackedPrinterList; @@ -103,6 +105,7 @@ final class RemotePrintService implements DeathRecipient { mSpooler = spooler; mHandler = new MyHandler(context.getMainLooper()); mPrintServiceClient = new RemotePrintServiceClient(this); + mServiceDead = true; } public ComponentName getComponentName() { @@ -144,10 +147,6 @@ final class RemotePrintService implements DeathRecipient { mDestroyed = true; } - public void onAllPrintJobsHandled() { - mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED); - } - @Override public void binderDied() { mHandler.sendEmptyMessage(MyHandler.MSG_BINDER_DIED); @@ -156,36 +155,35 @@ final class RemotePrintService implements DeathRecipient { private void handleBinderDied() { mPrintService.asBinder().unlinkToDeath(this, 0); mPrintService = null; + mServiceDead = true; mCallbacks.onServiceDied(this); } - public void dump(PrintWriter pw, String prefix) { - String tab = " "; - pw.append(prefix).append("service:").println(); - pw.append(prefix).append(tab).append("componentName=") - .append(mComponentName.flattenToString()).println(); - pw.append(prefix).append(tab).append("destroyed=") - .append(String.valueOf(mDestroyed)).println(); - pw.append(prefix).append(tab).append("bound=") - .append(String.valueOf(isBound())).println(); - pw.append(prefix).append(tab).append("hasDicoverySession=") - .append(String.valueOf(mHasPrinterDiscoverySession)).println(); - pw.append(prefix).append(tab).append("isDiscoveringPrinters=") - .append(String.valueOf(mDiscoveryPriorityList != null)).println(); - pw.append(prefix).append(tab).append("trackedPrinters=") - .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); + public void onAllPrintJobsHandled() { + mHandler.sendEmptyMessage(MyHandler.MSG_ON_ALL_PRINT_JOBS_HANDLED); } private void handleOnAllPrintJobsHandled() { throwIfDestroyed(); - mHasActivePrintJobs = false; - - if (isBound()) { + if (!isBound()) { + // The service is dead and neither has active jobs nor discovery + // session, so ensure we are unbound since the service has no work. + if (mServiceDead && !mHasPrinterDiscoverySession) { + ensureUnbound(); + return; + } + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleOnAllPrintJobsHandled(); + } + }); + } else { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] onAllPrintJobsHandled()"); } - // If the service has a printer discovery session // created we should not disconnect from it just yet. if (!mHasPrinterDiscoverySession) { @@ -201,9 +199,15 @@ final class RemotePrintService implements DeathRecipient { private void handleRequestCancelPrintJob(final PrintJobInfo printJob) { throwIfDestroyed(); - // If we are not bound, then we have no print jobs to handle - // which means that there are no print jobs to be cancelled. - if (isBound()) { + if (!isBound()) { + ensureBound(); + mPendingCommands.add(new Runnable() { + @Override + public void run() { + handleRequestCancelPrintJob(printJob); + } + }); + } else { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] requestCancelPrintJob()"); } @@ -222,14 +226,12 @@ final class RemotePrintService implements DeathRecipient { private void handleOnPrintJobQueued(final PrintJobInfo printJob) { throwIfDestroyed(); - mHasActivePrintJobs = true; - if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @Override - public void run() { + public void run() { handleOnPrintJobQueued(printJob); } }); @@ -251,6 +253,7 @@ final class RemotePrintService implements DeathRecipient { private void handleCreatePrinterDiscoverySession() { throwIfDestroyed(); + mHasPrinterDiscoverySession = true; if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -268,8 +271,6 @@ final class RemotePrintService implements DeathRecipient { } catch (RemoteException re) { Slog.e(LOG_TAG, "Error creating printer dicovery session.", re); } - - mHasPrinterDiscoverySession = true; } } @@ -279,7 +280,14 @@ final class RemotePrintService implements DeathRecipient { private void handleDestroyPrinterDiscoverySession() { throwIfDestroyed(); + mHasPrinterDiscoverySession = false; if (!isBound()) { + // The service is dead and neither has active jobs nor discovery + // session, so ensure we are unbound since the service has no work. + if (mServiceDead && !mHasActivePrintJobs) { + ensureUnbound(); + return; + } ensureBound(); mPendingCommands.add(new Runnable() { @Override @@ -291,15 +299,11 @@ final class RemotePrintService implements DeathRecipient { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] destroyPrinterDiscoverySession()"); } - - mHasPrinterDiscoverySession = false; - try { mPrintService.destroyPrinterDiscoverySession(); } catch (RemoteException re) { Slog.e(LOG_TAG, "Error destroying printer dicovery session.", re); } - // If the service has no print jobs and no active discovery // session anymore we should disconnect from it. if (!mHasActivePrintJobs) { @@ -315,6 +319,11 @@ final class RemotePrintService implements DeathRecipient { private void handleStartPrinterDiscovery(final List<PrinterId> priorityList) { throwIfDestroyed(); + // Take a note that we are doing discovery. + mDiscoveryPriorityList = new ArrayList<PrinterId>(); + if (priorityList != null) { + mDiscoveryPriorityList.addAll(priorityList); + } if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -332,11 +341,6 @@ final class RemotePrintService implements DeathRecipient { } catch (RemoteException re) { Slog.e(LOG_TAG, "Error starting printer dicovery.", re); } - // Take a note that we are doing discovery. - mDiscoveryPriorityList = new ArrayList<PrinterId>(); - if (priorityList != null) { - mDiscoveryPriorityList.addAll(priorityList); - } } } @@ -346,6 +350,8 @@ final class RemotePrintService implements DeathRecipient { private void handleStopPrinterDiscovery() { throwIfDestroyed(); + // We are not doing discovery anymore. + mDiscoveryPriorityList = null; if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -358,8 +364,6 @@ final class RemotePrintService implements DeathRecipient { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterDiscovery()"); } - // We are not doing discovery anymore. - mDiscoveryPriorityList = null; try { mPrintService.stopPrinterDiscovery(); } catch (RemoteException re) { @@ -402,6 +406,11 @@ final class RemotePrintService implements DeathRecipient { private void handleStartPrinterStateTracking(final PrinterId printerId) { throwIfDestroyed(); + // Take a note we are tracking the printer. + if (mTrackedPrinterList == null) { + mTrackedPrinterList = new ArrayList<PrinterId>(); + } + mTrackedPrinterList.add(printerId); if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -419,11 +428,6 @@ final class RemotePrintService implements DeathRecipient { } catch (RemoteException re) { Slog.e(LOG_TAG, "Error requesting start printer tracking.", re); } - // Take a note we are tracking the printer. - if (mTrackedPrinterList == null) { - mTrackedPrinterList = new ArrayList<PrinterId>(); - } - mTrackedPrinterList.add(printerId); } } @@ -434,6 +438,13 @@ final class RemotePrintService implements DeathRecipient { private void handleStopPrinterStateTracking(final PrinterId printerId) { throwIfDestroyed(); + // We are no longer tracking the printer. + if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) { + return; + } + if (mTrackedPrinterList.isEmpty()) { + mTrackedPrinterList = null; + } if (!isBound()) { ensureBound(); mPendingCommands.add(new Runnable() { @@ -446,13 +457,6 @@ final class RemotePrintService implements DeathRecipient { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserId + "] stopPrinterTracking()"); } - // We are no longer tracking the printer. - if (mTrackedPrinterList == null || !mTrackedPrinterList.remove(printerId)) { - return; - } - if (mTrackedPrinterList.isEmpty()) { - mTrackedPrinterList = null; - } try { mPrintService.stopPrinterStateTracking(printerId); } catch (RemoteException re) { @@ -461,6 +465,25 @@ final class RemotePrintService implements DeathRecipient { } } + public void dump(PrintWriter pw, String prefix) { + String tab = " "; + pw.append(prefix).append("service:").println(); + pw.append(prefix).append(tab).append("componentName=") + .append(mComponentName.flattenToString()).println(); + pw.append(prefix).append(tab).append("destroyed=") + .append(String.valueOf(mDestroyed)).println(); + pw.append(prefix).append(tab).append("bound=") + .append(String.valueOf(isBound())).println(); + pw.append(prefix).append(tab).append("hasDicoverySession=") + .append(String.valueOf(mHasPrinterDiscoverySession)).println(); + pw.append(prefix).append(tab).append("hasActivePrintJobs=") + .append(String.valueOf(mHasActivePrintJobs)).println(); + pw.append(prefix).append(tab).append("isDiscoveringPrinters=") + .append(String.valueOf(mDiscoveryPriorityList != null)).println(); + pw.append(prefix).append(tab).append("trackedPrinters=") + .append((mTrackedPrinterList != null) ? mTrackedPrinterList.toString() : "null"); + } + private boolean isBound() { return mPrintService != null; } @@ -512,6 +535,7 @@ final class RemotePrintService implements DeathRecipient { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (mDestroyed || !mBinding) { + mContext.unbindService(mServiceConnection); return; } mBinding = false; @@ -529,31 +553,33 @@ final class RemotePrintService implements DeathRecipient { handleBinderDied(); return; } - // If there is a session, then the service died after creating - // a session. Hence, recreate the session. - if (mHasPrinterDiscoverySession) { + // If the service died and there is a discovery session, recreate it. + if (mServiceDead && mHasPrinterDiscoverySession) { handleCreatePrinterDiscoverySession(); } - // If there is a priority list, then the service died during - // discovery and is restarted. Hence, start discovery. - if (mDiscoveryPriorityList != null) { + // If the service died and there is discovery started, restart it. + if (mServiceDead && mDiscoveryPriorityList != null) { handleStartPrinterDiscovery(mDiscoveryPriorityList); } - // If there is a tracked printer list, then the service died - // during discovery and is restarted. Hence, start tracking. - if (mTrackedPrinterList != null) { + // If the service died and printers were tracked, start tracking. + if (mServiceDead && mTrackedPrinterList != null) { final int trackedPrinterCount = mTrackedPrinterList.size(); for (int i = 0; i < trackedPrinterCount; i++) { handleStartPrinterStateTracking(mTrackedPrinterList.get(i)); } } // Finally, do all the pending work. - final int pendingCommandCount = mPendingCommands.size(); - for (int i = 0; i < pendingCommandCount; i++) { - Runnable pendingCommand = mPendingCommands.get(i); + while (!mPendingCommands.isEmpty()) { + Runnable pendingCommand = mPendingCommands.remove(0); pendingCommand.run(); } - mPendingCommands.clear(); + // We did a best effort to get to the last state if we crashed. + // If we do not have print jobs and no discovery is in progress, + // then no need to be bound. + if (!mHasPrinterDiscoverySession && !mHasActivePrintJobs) { + ensureUnbound(); + } + mServiceDead = false; } @Override diff --git a/services/java/com/android/server/print/UserState.java b/services/java/com/android/server/print/UserState.java index 86a5aed..7a56e6b 100644 --- a/services/java/com/android/server/print/UserState.java +++ b/services/java/com/android/server/print/UserState.java @@ -134,6 +134,26 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { } } + public List<PrintServiceInfo> getEnabledPrintServices() { + synchronized (mLock) { + List<PrintServiceInfo> enabledServices = null; + final int installedServiceCount = mInstalledServices.size(); + for (int i = 0; i < installedServiceCount; i++) { + PrintServiceInfo installedService = mInstalledServices.get(i); + ComponentName componentName = new ComponentName( + installedService.getResolveInfo().serviceInfo.packageName, + installedService.getResolveInfo().serviceInfo.name); + if (mActiveServices.containsKey(componentName)) { + if (enabledServices == null) { + enabledServices = new ArrayList<PrintServiceInfo>(); + } + enabledServices.add(installedService); + } + } + return enabledServices; + } + } + public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) { synchronized (mLock) { throwIfDestroyedLocked(); @@ -292,6 +312,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { } // Fail all print jobs. failActivePrintJobsForService(service.getComponentName()); + service.onAllPrintJobsHandled(); // No session - nothing to do. if (mPrinterDiscoverySession == null) { return; @@ -984,11 +1005,11 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { removedPrinterIds.add(printerId); } } - final int removedPrinterCount = removedPrinterIds.size(); - for (int i = 0; i < removedPrinterCount; i++) { - mPrinters.remove(removedPrinterIds.get(i)); - } if (removedPrinterIds != null) { + final int removedPrinterCount = removedPrinterIds.size(); + for (int i = 0; i < removedPrinterCount; i++) { + mPrinters.remove(removedPrinterIds.get(i)); + } mHandler.obtainMessage( SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED, removedPrinterIds).sendToTarget(); |