diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index fb6bb2e9ec906..d2ae5e6f92f2a 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 getEnabledPrintServices(int userId);
+
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
in List priorityList, int userId);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 6e32c05fc24cd..10cc7715c5994 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;
@@ -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 getEnabledPrintServices() {
+ try {
+ List 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
*/
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 012e76ab9dd18..e5ebf7754cf63 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}.
*
+ *
+ * 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 true
+ * . 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.
+ *
*/
public static final String SERVICE_META_DATA = "android.printservice";
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 83ec1adf33fee..9319025df92c1 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -22,17 +22,24 @@
android:versionCode="1">
+ on the device. Usually an app can access only the print jobs it created. -->
+
+
+
-
+
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 235a7a1b44ece..21a48673eb753 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -145,4 +145,12 @@
Allows the holder to access print jobs
created by another app. Should never be needed for normal apps.
+
+ start print service configuration activities
+
+ Allows the holder to start the
+ configuration activities of a print service. Should never be needed for normal apps.
+
diff --git a/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java b/packages/PrintSpooler/src/com/android/printspooler/PrintJobConfigActivity.java
index 5c3d70037c79f..14f60f177438e 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 9ca3a869626a8..c397c40655308 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 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 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 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 926f822d0edae..c33bfb78e099e 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 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/UserState.java b/services/java/com/android/server/print/UserState.java
index 86a5aedc3ebc1..6b68c617119f9 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 getEnabledPrintServices() {
+ synchronized (mLock) {
+ List 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();
+ }
+ enabledServices.add(installedService);
+ }
+ }
+ return enabledServices;
+ }
+ }
+
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();