Merge changes Id0a67846,I20b57d66 into klp-dev
* changes: Print system may get stuck bound to a print service Spooler should not crash if print service config activities are not exported.
This commit is contained in:
committed by
Android (Google) Code Review
commit
4244d66a12
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -203,6 +204,25 @@ public final class PrintManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user