diff --git a/Android.mk b/Android.mk
index 3ac5889f61c33..e39ff3bbb3c0a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -246,6 +246,7 @@ LOCAL_SRC_FILES += \
core/java/android/print/IPrintDocumentAdapter.aidl \
core/java/android/print/IPrintDocumentAdapterObserver.aidl \
core/java/android/print/IPrintJobStateChangeListener.aidl \
+ core/java/android/print/IPrintServicesChangeListener.aidl \
core/java/android/print/IPrintManager.aidl \
core/java/android/print/IPrintSpooler.aidl \
core/java/android/print/IPrintSpoolerCallbacks.aidl \
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 9a80e375ceb22..5eb8cc2f37a40 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -16,12 +16,14 @@
package android.print;
+import android.content.ComponentName;
import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.print.IPrinterDiscoveryObserver;
import android.print.IPrintDocumentAdapter;
import android.print.PrintJobId;
import android.print.IPrintJobStateChangeListener;
+import android.print.IPrintServicesChangeListener;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
@@ -45,8 +47,47 @@ interface IPrintManager {
void removePrintJobStateChangeListener(in IPrintJobStateChangeListener listener,
int userId);
- List getInstalledPrintServices(int userId);
- List getEnabledPrintServices(int userId);
+ /**
+ * Listen for changes to the installed and enabled print services.
+ *
+ * @param listener the listener to add
+ * @param userId the id of the user listening
+ *
+ * @see android.print.PrintManager#getPrintServices(int, String)
+ */
+ void addPrintServicesChangeListener(in IPrintServicesChangeListener listener,
+ int userId);
+
+ /**
+ * Stop listening for changes to the installed and enabled print services.
+ *
+ * @param listener the listener to remove
+ * @param userId the id of the user requesting the removal
+ *
+ * @see android.print.PrintManager#getPrintServices(int, String)
+ */
+ void removePrintServicesChangeListener(in IPrintServicesChangeListener listener,
+ int userId);
+
+ /**
+ * Get the print services.
+ *
+ * @param selectionFlags flags selecting which services to get
+ * @param selectedService if not null, the id of the print service to get
+ * @param userId the id of the user requesting the services
+ *
+ * @return the list of selected print services.
+ */
+ List getPrintServices(int selectionFlags, int userId);
+
+ /**
+ * Enable or disable a print service.
+ *
+ * @param service The service to enabled or disable
+ * @param isEnabled whether the service should be enabled or disabled
+ * @param userId the id of the user requesting the services
+ */
+ void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
diff --git a/core/java/android/print/IPrintServicesChangeListener.aidl b/core/java/android/print/IPrintServicesChangeListener.aidl
new file mode 100644
index 0000000000000..2a7ce89af98ec
--- /dev/null
+++ b/core/java/android/print/IPrintServicesChangeListener.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+/**
+ * Interface for observing print services changes.
+ *
+ * @hide
+ */
+oneway interface IPrintServicesChangeListener {
+ void onPrintServicesChanged();
+}
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 0540036f1a496..25fc968fec5a7 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -20,6 +20,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.ComponentName;
import android.content.Context;
import android.content.IntentSender;
import android.content.IntentSender.SendIntentException;
@@ -111,6 +112,38 @@ public final class PrintManager {
private static final boolean DEBUG = false;
private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
+ private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
+
+ /**
+ * Package name of print spooler.
+ *
+ * @hide
+ */
+ public static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
+
+ /**
+ * Select enabled services.
+ *
+ * @see #getPrintServices
+ * @hide
+ */
+ public static final int ENABLED_SERVICES = 1 << 0;
+
+ /**
+ * Select disabled services.
+ *
+ * @see #getPrintServices
+ * @hide
+ */
+ public static final int DISABLED_SERVICES = 1 << 1;
+
+ /**
+ * Select all services.
+ *
+ * @see #getPrintServices
+ * @hide
+ */
+ public static final int ALL_SERVICES = ENABLED_SERVICES | DISABLED_SERVICES;
/**
* The action for launching the print dialog activity.
@@ -165,7 +198,10 @@ public final class PrintManager {
private final Handler mHandler;
- private Map mPrintJobStateChangeListeners;
+ private Map
+ mPrintJobStateChangeListeners;
+ private Map
+ mPrintServicesChangeListeners;
/** @hide */
public interface PrintJobStateChangeListener {
@@ -178,6 +214,15 @@ public final class PrintManager {
public void onPrintJobStateChanged(PrintJobId printJobId);
}
+ /** @hide */
+ public interface PrintServicesChangeListener {
+
+ /**
+ * Callback notifying that the print services changed.
+ */
+ public void onPrintServicesChanged();
+ }
+
/**
* Creates a new instance.
*
@@ -207,6 +252,15 @@ public final class PrintManager {
}
args.recycle();
} break;
+ case MSG_NOTIFY_PRINT_SERVICES_CHANGED: {
+ PrintServicesChangeListenerWrapper wrapper =
+ (PrintServicesChangeListenerWrapper) message.obj;
+ PrintServicesChangeListener listener = wrapper.getListener();
+ if (listener != null) {
+ listener.onPrintServicesChanged();
+ }
+ } break;
+
}
}
};
@@ -478,42 +532,82 @@ public final class PrintManager {
}
/**
- * Gets the list of enabled print services.
+ * Listen for changes to the installed and enabled print services.
*
- * @return The enabled service list or an empty list.
- * @hide
+ * @param listener the listener to add
+ *
+ * @see android.print.PrintManager#getPrintServices
*/
- public List getEnabledPrintServices() {
+ void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
- return Collections.emptyList();
+ return;
}
+ if (mPrintServicesChangeListeners == null) {
+ mPrintServicesChangeListeners = new ArrayMap();
+ }
+ PrintServicesChangeListenerWrapper wrappedListener =
+ new PrintServicesChangeListenerWrapper(listener, mHandler);
try {
- List enabledServices = mService.getEnabledPrintServices(mUserId);
- if (enabledServices != null) {
- return enabledServices;
- }
+ mService.addPrintServicesChangeListener(wrappedListener, mUserId);
+ mPrintServicesChangeListeners.put(listener, wrappedListener);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
- return Collections.emptyList();
}
/**
- * Gets the list of installed print services.
+ * Stop listening for changes to the installed and enabled print services.
*
- * @return The installed service list or an empty list.
- * @hide
+ * @param listener the listener to remove
+ *
+ * @see android.print.PrintManager#getPrintServices
*/
- public List getInstalledPrintServices() {
+ void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
- return Collections.emptyList();
+ return;
}
+ if (mPrintServicesChangeListeners == null) {
+ return;
+ }
+ PrintServicesChangeListenerWrapper wrappedListener =
+ mPrintServicesChangeListeners.remove(listener);
+ if (wrappedListener == null) {
+ return;
+ }
+ if (mPrintServicesChangeListeners.isEmpty()) {
+ mPrintServicesChangeListeners = null;
+ }
+ wrappedListener.destroy();
try {
- List installedServices = mService.getInstalledPrintServices(mUserId);
- if (installedServices != null) {
- return installedServices;
+ mService.removePrintServicesChangeListener(wrappedListener, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error removing print services change listener", re);
+ }
+ }
+
+
+ /**
+ * Gets the list of print services, but does not register for updates. The user has to register
+ * for updates by itself, or use {@link PrintServicesLoader}.
+ *
+ * @param selectionFlags flags selecting which services to get. Either
+ * {@link #ENABLED_SERVICES},{@link #DISABLED_SERVICES}, or both.
+ *
+ * @return The enabled service list or an empty list.
+ *
+ * @see #addPrintServicesChangeListener(PrintServicesChangeListener)
+ * @see #removePrintServicesChangeListener(PrintServicesChangeListener)
+ *
+ * @hide
+ */
+ public @NonNull List getPrintServices(int selectionFlags) {
+ try {
+ List services = mService.getPrintServices(selectionFlags, mUserId);
+ if (services != null) {
+ return services;
}
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -532,6 +626,26 @@ public final class PrintManager {
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
+ /**
+ * Enable or disable a print service.
+ *
+ * @param service The service to enabled or disable
+ * @param isEnabled whether the service should be enabled or disabled
+ *
+ * @hide
+ */
+ public void setPrintServiceEnabled(@NonNull ComponentName service, boolean isEnabled) {
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
+ try {
+ mService.setPrintServiceEnabled(service, isEnabled, mUserId);
+ } catch (RemoteException re) {
+ Log.e(LOG_TAG, "Error enabling or disabling " + service, re);
+ }
+ }
+
/**
* @hide
*/
@@ -1096,4 +1210,36 @@ public final class PrintManager {
return mWeakListener.get();
}
}
+
+ /**
+ * @hide
+ */
+ public static final class PrintServicesChangeListenerWrapper extends
+ IPrintServicesChangeListener.Stub {
+ private final WeakReference mWeakListener;
+ private final WeakReference mWeakHandler;
+
+ public PrintServicesChangeListenerWrapper(PrintServicesChangeListener listener,
+ Handler handler) {
+ mWeakListener = new WeakReference<>(listener);
+ mWeakHandler = new WeakReference<>(handler);
+ }
+
+ @Override
+ public void onPrintServicesChanged() {
+ Handler handler = mWeakHandler.get();
+ PrintServicesChangeListener listener = mWeakListener.get();
+ if (handler != null && listener != null) {
+ handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICES_CHANGED, this).sendToTarget();
+ }
+ }
+
+ public void destroy() {
+ mWeakListener.clear();
+ }
+
+ public PrintServicesChangeListener getListener() {
+ return mWeakListener.get();
+ }
+ }
}
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
new file mode 100644
index 0000000000000..ed411141d1fbd
--- /dev/null
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.print;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.Loader;
+import android.os.Handler;
+import android.os.Message;
+import android.printservice.PrintServiceInfo;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print services. Can be parametrized to select a subset.
+ *
+ * @hide
+ */
+public class PrintServicesLoader extends Loader> {
+ /** What type of services to load. */
+ private final int mSelectionFlags;
+
+ /** The print manager to be used by this object */
+ private final @NonNull PrintManager mPrintManager;
+
+ /** Handler to sequentialize the delivery of the results to the main thread */
+ private Handler mHandler;
+
+ /** Listens for updates to the data from the platform */
+ private PrintManager.PrintServicesChangeListener mListener;
+
+ /**
+ * Create a new PrintServicesLoader.
+ *
+ * @param selectionFlags What type of services to load.
+ */
+ public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
+ int selectionFlags) {
+ super(context);
+ mPrintManager = printManager;
+ mSelectionFlags = selectionFlags;
+ }
+
+ @Override
+ protected void onForceLoad() {
+ queueNewResult();
+ }
+
+ /**
+ * Read the print services and queue it to be delivered on the main thread.
+ */
+ private void queueNewResult() {
+ Message m = mHandler.obtainMessage(0);
+ m.obj = mPrintManager.getPrintServices(mSelectionFlags);
+ mHandler.sendMessage(m);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ mHandler = new MyHandler();
+ mListener = new PrintManager.PrintServicesChangeListener() {
+ @Override public void onPrintServicesChanged() {
+ queueNewResult();
+ }
+ };
+
+ mPrintManager.addPrintServicesChangeListener(mListener);
+
+ // Immediately deliver a result
+ deliverResult(mPrintManager.getPrintServices(mSelectionFlags));
+ }
+
+ @Override
+ protected void onStopLoading() {
+ if (mListener != null) {
+ mPrintManager.removePrintServicesChangeListener(mListener);
+ mListener = null;
+ }
+
+ if (mHandler != null) {
+ mHandler.removeMessages(0);
+ mHandler = null;
+ }
+ }
+
+ @Override
+ protected void onReset() {
+ onStopLoading();
+ }
+
+ /**
+ * Handler to sequentialize all the updates to the main thread.
+ */
+ private class MyHandler extends Handler {
+ /**
+ * Create a new handler on the main thread.
+ */
+ public MyHandler() {
+ super(getContext().getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+
+ if (isStarted()) {
+ deliverResult((List) msg.obj);
+ }
+ }
+ }
+}
diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java
index 91e01f2dfd8ba..45e3d47c39dee 100644
--- a/core/java/android/printservice/PrintServiceInfo.java
+++ b/core/java/android/printservice/PrintServiceInfo.java
@@ -55,6 +55,8 @@ public final class PrintServiceInfo implements Parcelable {
private final String mId;
+ private boolean mIsEnabled;
+
private final ResolveInfo mResolveInfo;
private final String mSettingsActivityName;
@@ -70,6 +72,7 @@ public final class PrintServiceInfo implements Parcelable {
*/
public PrintServiceInfo(Parcel parcel) {
mId = parcel.readString();
+ mIsEnabled = parcel.readByte() != 0;
mResolveInfo = parcel.readParcelable(null);
mSettingsActivityName = parcel.readString();
mAddPrintersActivityName = parcel.readString();
@@ -179,6 +182,24 @@ public final class PrintServiceInfo implements Parcelable {
return mId;
}
+ /**
+ * If the service was enabled when it was read from the system.
+ *
+ * @return The id.
+ */
+ public boolean isEnabled() {
+ return mIsEnabled;
+ }
+
+ /**
+ * Mark a service as enabled or not
+ *
+ * @param isEnabled If the service should be marked as enabled.
+ */
+ public void setIsEnabled(boolean isEnabled) {
+ mIsEnabled = isEnabled;
+ }
+
/**
* The service {@link ResolveInfo}.
*
@@ -238,6 +259,7 @@ public final class PrintServiceInfo implements Parcelable {
@Override
public void writeToParcel(Parcel parcel, int flagz) {
parcel.writeString(mId);
+ parcel.writeByte((byte)(mIsEnabled ? 1 : 0));
parcel.writeParcelable(mResolveInfo, 0);
parcel.writeString(mSettingsActivityName);
parcel.writeString(mAddPrintersActivityName);
@@ -276,6 +298,7 @@ public final class PrintServiceInfo implements Parcelable {
StringBuilder builder = new StringBuilder();
builder.append("PrintServiceInfo{");
builder.append("id=").append(mId);
+ builder.append("isEnabled=").append(mIsEnabled);
builder.append(", resolveInfo=").append(mResolveInfo);
builder.append(", settingsActivityName=").append(mSettingsActivityName);
builder.append(", addPrintersActivityName=").append(mAddPrintersActivityName);
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
index 3feb0e905f1a8..c9bc8aaae0cb7 100644
--- a/core/tests/coretests/src/android/print/BasePrintTest.java
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -61,7 +61,6 @@ import java.util.concurrent.TimeoutException;
public abstract class BasePrintTest extends InstrumentationTestCase {
private static final long OPERATION_TIMEOUT = 30000;
- private static final String PRINT_SPOOLER_PACKAGE_NAME = "com.android.printspooler";
private static final String PM_CLEAR_SUCCESS_OUTPUT = "Success";
private static final String COMMAND_LIST_ENABLED_IME_COMPONENTS = "ime list -s";
private static final String COMMAND_PREFIX_ENABLE_IME = "ime enable ";
@@ -249,8 +248,9 @@ public abstract class BasePrintTest extends InstrumentationTestCase {
protected void clearPrintSpoolerData() throws Exception {
assertTrue("failed to clear print spooler data",
runShellCommand(getInstrumentation(), String.format(
- "pm clear --user %d %s", CURRENT_USER_ID, PRINT_SPOOLER_PACKAGE_NAME))
- .contains(PM_CLEAR_SUCCESS_OUTPUT));
+ "pm clear --user %d %s", CURRENT_USER_ID,
+ PrintManager.PRINT_SPOOLER_PACKAGE_NAME))
+ .contains(PM_CLEAR_SUCCESS_OUTPUT));
}
@SuppressWarnings("unchecked")
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
index 5179b42fd650d..cbf17a43dbc6f 100644
--- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -27,24 +27,9 @@ import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.ServiceManager;
import android.os.UserHandle;
-import android.print.IPrintDocumentAdapter;
-import android.print.IPrintJobStateChangeListener;
-import android.print.IPrintManager;
-import android.print.IPrinterDiscoveryObserver;
-import android.print.PageRange;
-import android.print.PrintAttributes;
import android.print.PrintAttributes.Margins;
import android.print.PrintAttributes.MediaSize;
import android.print.PrintAttributes.Resolution;
-import android.print.PrintDocumentAdapter;
-import android.print.PrintJob;
-import android.print.PrintJobId;
-import android.print.PrintJobInfo;
-import android.print.PrintManager;
-import android.print.PrinterCapabilitiesInfo;
-import android.print.PrinterDiscoverySession;
-import android.print.PrinterId;
-import android.print.PrinterInfo;
import android.printservice.PrintServiceInfo;
import android.print.mockservice.MockPrintService;
@@ -134,7 +119,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
if (session.getPrinters().isEmpty()) {
final String PRINTER_NAME = "good printer";
- List printers = new ArrayList();
+ List printers = new ArrayList<>();
// Add the printer.
mGoodPrinterId = session.getService()
@@ -183,6 +168,18 @@ public class IPrintManagerParametersTest extends BasePrintTest {
new Handler(Looper.getMainLooper()));
}
+ /**
+ * Create a IPrintServicesChangeListener object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IPrintServicesChangeListener createMockIPrintServicesChangeListener() throws Exception {
+ return new PrintManager.PrintServicesChangeListenerWrapper(null,
+ new Handler(Looper.getMainLooper()));
+ }
+
+
/**
* Create a IPrinterDiscoveryObserver object.
*
@@ -193,6 +190,16 @@ public class IPrintManagerParametersTest extends BasePrintTest {
return new PrinterDiscoverySession.PrinterDiscoveryObserver(null);
}
+ private void startPrinting() {
+ mGoodPrintJob = print(createMockAdapter(), null);
+
+ // Wait for PrintActivity to be ready
+ waitForStartAdapterCallbackCalled();
+
+ // Wait for printer discovery session to be ready
+ waitForPrinterDiscoverySessionStartCallbackCalled();
+ }
+
@Override
public void setUp() throws Exception {
super.setUp();
@@ -201,20 +208,12 @@ public class IPrintManagerParametersTest extends BasePrintTest {
mGoodComponentName = getActivity().getComponentName();
- mGoodPrintJob = print(createMockAdapter(), null);
-
mIPrintManager = IPrintManager.Stub
.asInterface(ServiceManager.getService(Context.PRINT_SERVICE));
// Generate dummy printerId which is a valid PrinterId object, but does not correspond to a
// printer
mBadPrinterId = new PrinterId(mGoodComponentName, "dummy printer");
-
- // Wait for PrintActivity to be ready
- waitForStartAdapterCallbackCalled();
-
- // Wait for printer discovery session to be ready
- waitForPrinterDiscoverySessionStartCallbackCalled();
}
/**
@@ -222,11 +221,11 @@ public class IPrintManagerParametersTest extends BasePrintTest {
*/
private interface Invokable {
/**
- * Execute the {@link Invokable}
+ * Execute the invokable
*
* @throws Exception
*/
- public void run() throws Exception;
+ void run() throws Exception;
}
/**
@@ -255,6 +254,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.getPrintJobInfo
*/
public void testGetPrintJobInfo() throws Exception {
+ startPrinting();
+
assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
mAppId, mUserId).getId());
assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
@@ -274,6 +275,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.getPrintJobInfos
*/
public void testGetPrintJobInfos() throws Exception {
+ startPrinting();
+
List infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
boolean foundPrintJob = false;
@@ -304,7 +307,7 @@ public class IPrintManagerParametersTest extends BasePrintTest {
final IPrintDocumentAdapter adapter = new PrintManager
.PrintDocumentAdapterDelegate(getActivity(), createMockAdapter());
- // Valid parameters are tested in setUp()
+ startPrinting();
assertException(new Invokable() {
@Override
@@ -352,6 +355,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.cancelPrintJob
*/
public void testCancelPrintJob() throws Exception {
+ startPrinting();
+
// Invalid print jobs IDs do not produce an exception
mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
@@ -373,6 +378,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.restartPrintJob
*/
public void testRestartPrintJob() throws Exception {
+ startPrinting();
+
mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
// Invalid print jobs IDs do not produce an exception
@@ -438,22 +445,103 @@ public class IPrintManagerParametersTest extends BasePrintTest {
}
/**
- * test IPrintManager.getInstalledPrintServices
+ * test IPrintManager.addPrintServicesChangeListener
*/
- public void testGetInstalledPrintServices() throws Exception {
- List printServices = mIPrintManager.getInstalledPrintServices(mUserId);
- assertTrue(printServices.size() >= 2);
+ public void testAddPrintServicesChangeListener() throws Exception {
+ final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
+
+ mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintServicesChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
// Cannot test bad user Id as these tests are allowed to call across users
}
/**
- * test IPrintManager.getEnabledPrintServices
+ * test IPrintManager.removePrintServicesChangeListener
*/
- public void testGetEnabledPrintServices() throws Exception {
- List printServices = mIPrintManager.getEnabledPrintServices(mUserId);
+ public void testRemovePrintServicesChangeListener() throws Exception {
+ final IPrintServicesChangeListener listener = createMockIPrintServicesChangeListener();
+
+ mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+ mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
+
+ // Removing unknown listeners is a no-op
+ mIPrintManager.removePrintServicesChangeListener(listener, mUserId);
+
+ mIPrintManager.addPrintServicesChangeListener(listener, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.removePrintServicesChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getPrintServices
+ */
+ public void testGetPrintServices() throws Exception {
+ List printServices = mIPrintManager.getPrintServices(
+ PrintManager.ALL_SERVICES, mUserId);
assertTrue(printServices.size() >= 2);
+ printServices = mIPrintManager.getPrintServices(0, mUserId);
+ assertEquals(printServices, null);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getPrintServices(~PrintManager.ALL_SERVICES, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.setPrintServiceEnabled
+ */
+ public void testSetPrintServiceEnabled() throws Exception {
+ final ComponentName printService = mIPrintManager.getPrintServices(
+ PrintManager.ALL_SERVICES, mUserId).get(0).getComponentName();
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(printService, false, mUserId);
+ }
+ }, SecurityException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(printService, true, mUserId);
+ }
+ }, SecurityException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(new ComponentName("bad", "name"), true,
+ mUserId);
+ }
+ }, SecurityException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.setPrintServiceEnabled(null, true, mUserId);
+ }
+ }, SecurityException.class);
+
// Cannot test bad user Id as these tests are allowed to call across users
}
@@ -486,6 +574,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.startPrinterDiscovery
*/
public void testStartPrinterDiscovery() throws Exception {
+ startPrinting();
+
final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
final List goodPrinters = new ArrayList<>();
goodPrinters.add(mGoodPrinterId);
@@ -549,6 +639,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.validatePrinters
*/
public void testValidatePrinters() throws Exception {
+ startPrinting();
+
final List goodPrinters = new ArrayList<>();
goodPrinters.add(mGoodPrinterId);
@@ -587,6 +679,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.startPrinterStateTracking
*/
public void testStartPrinterStateTracking() throws Exception {
+ startPrinting();
+
mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
// Bad printers do no cause exceptions
@@ -606,6 +700,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.getCustomPrinterIcon
*/
public void testGetCustomPrinterIcon() throws Exception {
+ startPrinting();
+
mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
// Bad printers do no cause exceptions
@@ -625,6 +721,8 @@ public class IPrintManagerParametersTest extends BasePrintTest {
* test IPrintManager.stopPrinterStateTracking
*/
public void testStopPrinterStateTracking() throws Exception {
+ startPrinting();
+
mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index af9d25196bec5..1bdb6d8bc4a7c 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -63,7 +63,7 @@
android:name=".ui.PrintActivity"
android:configChanges="screenSize|smallestScreenSize|orientation"
android:permission="android.permission.BIND_PRINT_SPOOLER_SERVICE"
- android:theme="@style/PrintActivity">
+ android:theme="@style/Theme.PrintActivity">
@@ -74,7 +74,14 @@
+
+
+
diff --git a/packages/PrintSpooler/res/drawable/ic_add.xml b/packages/PrintSpooler/res/drawable/ic_add.xml
index 1442b1b61f467..f728e7d0668e8 100644
--- a/packages/PrintSpooler/res/drawable/ic_add.xml
+++ b/packages/PrintSpooler/res/drawable/ic_add.xml
@@ -21,5 +21,5 @@
android:viewportHeight="24.0">
+ android:fillColor="?android:attr/colorAccent"/>
\ No newline at end of file
diff --git a/packages/PrintSpooler/res/drawable/ic_print.xml b/packages/PrintSpooler/res/drawable/ic_print.xml
index dc6e0fbc1d23c..e5e4d075f0192 100644
--- a/packages/PrintSpooler/res/drawable/ic_print.xml
+++ b/packages/PrintSpooler/res/drawable/ic_print.xml
@@ -16,4 +16,4 @@
+ android:tint="?android:attr/colorAccent" />
diff --git a/packages/PrintSpooler/res/drawable/page_selector_background.xml b/packages/PrintSpooler/res/drawable/page_selector_background.xml
index 7f1da314e1eee..4d32328efdc90 100644
--- a/packages/PrintSpooler/res/drawable/page_selector_background.xml
+++ b/packages/PrintSpooler/res/drawable/page_selector_background.xml
@@ -22,14 +22,14 @@
android:state_selected="true">
+ android:tint="?android:attr/colorAccent">
+ android:tint="?android:attr/colorAccent">
diff --git a/packages/PrintSpooler/res/drawable/print_button_background.xml b/packages/PrintSpooler/res/drawable/print_button_background.xml
index aec84744af13c..ad16547252aeb 100644
--- a/packages/PrintSpooler/res/drawable/print_button_background.xml
+++ b/packages/PrintSpooler/res/drawable/print_button_background.xml
@@ -18,7 +18,7 @@
android:shape="oval">
+ android:color="?android:attr/colorAccent">
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/layout/add_printer_list_header.xml b/packages/PrintSpooler/res/layout/add_printer_list_header.xml
new file mode 100644
index 0000000000000..ff342cbbb0fa1
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_list_header.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/layout/add_printer_list_item.xml b/packages/PrintSpooler/res/layout/add_printer_list_item.xml
new file mode 100644
index 0000000000000..1a2e774d2474b
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/add_printer_list_item.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/layout/all_print_services_list_item.xml b/packages/PrintSpooler/res/layout/all_print_services_list_item.xml
new file mode 100644
index 0000000000000..a2471c64b56e9
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/all_print_services_list_item.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml b/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml
new file mode 100644
index 0000000000000..73d09333bf808
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/disabled_print_services_list_item.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml b/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml
new file mode 100644
index 0000000000000..c13487a4851a1
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/enabled_print_services_list_item.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
index defbf8db0026b..103c157b873f1 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_item.xml
@@ -16,10 +16,8 @@
@@ -33,10 +31,9 @@
android:visibility="invisible">
-
@@ -47,8 +44,6 @@
android:textAppearance="?android:attr/textAppearanceMedium"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
- android:gravity="top|start"
android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
@@ -57,15 +52,15 @@
android:id="@+id/subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_below="@id/title"
android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
android:visibility="gone"
android:textColor="?android:attr/textColorSecondary"
android:duplicateParentState="true">
-
+
diff --git a/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml b/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
index 11fef2d21fde3..60f7088346286 100644
--- a/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
+++ b/packages/PrintSpooler/res/layout/printer_dropdown_prompt.xml
@@ -16,13 +16,10 @@
diff --git a/packages/PrintSpooler/res/layout/printer_list_item.xml b/packages/PrintSpooler/res/layout/printer_list_item.xml
index 1209aa6f0fa2d..0784bab589bc6 100644
--- a/packages/PrintSpooler/res/layout/printer_list_item.xml
+++ b/packages/PrintSpooler/res/layout/printer_list_item.xml
@@ -16,10 +16,9 @@
@@ -28,18 +27,15 @@
android:layout_width="40dip"
android:layout_height="40dip"
android:layout_gravity="center_vertical"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
android:duplicateParentState="true"
android:contentDescription="@null"
android:visibility="invisible">
@@ -47,15 +43,9 @@
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAppearance="?android:attr/textAppearanceListItem"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
- android:layout_alignParentTop="true"
- android:layout_alignParentStart="true"
- android:fadingEdge="horizontal"
- android:textAlignment="viewStart"
- android:textColor="?android:attr/textColorPrimary"
android:duplicateParentState="true">
@@ -64,30 +54,31 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
- android:layout_alignParentStart="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="?android:attr/textAppearanceListItemSecondary"
android:singleLine="true"
android:ellipsize="end"
- android:textIsSelectable="false"
android:visibility="gone"
- android:textColor="?android:attr/textColorSecondary"
- android:textAlignment="viewStart"
android:duplicateParentState="true">
-
+
-
+
+
+
diff --git a/packages/PrintSpooler/res/layout/select_printer_activity.xml b/packages/PrintSpooler/res/layout/select_printer_activity.xml
index 77c500ab86b20..564802ae11ab8 100644
--- a/packages/PrintSpooler/res/layout/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/layout/select_printer_activity.xml
@@ -22,11 +22,7 @@
-
+ android:layout_height="fill_parent" />
+ style="?android:attr/progressBarStyleHorizontal">
+
+
diff --git a/packages/PrintSpooler/res/menu/select_printer_activity.xml b/packages/PrintSpooler/res/menu/select_printer_activity.xml
index 15cc13939cf0e..60dfdcaf19649 100644
--- a/packages/PrintSpooler/res/menu/select_printer_activity.xml
+++ b/packages/PrintSpooler/res/menu/select_printer_activity.xml
@@ -26,12 +26,4 @@
android:imeOptions="actionSearch">
-
-
-
diff --git a/packages/PrintSpooler/res/values/colors.xml b/packages/PrintSpooler/res/values/colors.xml
index d1bec32cf1bb7..47e616ef40c77 100644
--- a/packages/PrintSpooler/res/values/colors.xml
+++ b/packages/PrintSpooler/res/values/colors.xml
@@ -22,8 +22,6 @@
#F2F1F2
- #FF80CBC4
-
#ffa3a3a3
diff --git a/packages/PrintSpooler/res/values/donottranslate.xml b/packages/PrintSpooler/res/values/donottranslate.xml
index 8069a1da89b32..589043b02517a 100644
--- a/packages/PrintSpooler/res/values/donottranslate.xml
+++ b/packages/PrintSpooler/res/values/donottranslate.xml
@@ -25,4 +25,6 @@
ISO_A4@string/mediasize_standard_iso
+ market://details?id=%1$s
+
diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml
index 76292a16e9b14..4b566221e4fad 100644
--- a/packages/PrintSpooler/res/values/strings.xml
+++ b/packages/PrintSpooler/res/values/strings.xml
@@ -129,7 +129,7 @@
Search box hidden
-
+
Add printer
@@ -151,12 +151,7 @@
More information about this printer
- Some print services are disabled.
-
-
-
-
- Choose print service
+ Some print services are disabledSearching for printers
@@ -167,6 +162,29 @@
No printers found
+
+
+
+ Cannot add printers
+
+
+ Select to add printer
+
+
+ Select to enable
+
+
+ Enabled services
+
+
+ Recommended services
+
+
+ Disabled services
+
+
+ All services
+
diff --git a/packages/PrintSpooler/res/values/styles.xml b/packages/PrintSpooler/res/values/styles.xml
new file mode 100644
index 0000000000000..1e63a67e50a44
--- /dev/null
+++ b/packages/PrintSpooler/res/values/styles.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml
index 05de5b79a6f9b..a968ffa9ed1d6 100644
--- a/packages/PrintSpooler/res/values/themes.xml
+++ b/packages/PrintSpooler/res/values/themes.xml
@@ -15,8 +15,17 @@
-->
+
-
+
+