summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/print/PrintManager.java10
-rw-r--r--core/java/android/print/PrinterDiscoverySession.java10
-rw-r--r--core/java/android/printservice/PrintService.java3
-rw-r--r--core/java/com/android/internal/util/Preconditions.java21
-rw-r--r--core/tests/coretests/Android.mk3
-rw-r--r--core/tests/coretests/AndroidManifest.xml20
-rw-r--r--core/tests/coretests/res/xml/printservice.xml20
-rw-r--r--core/tests/coretests/src/android/print/BasePrintTest.java361
-rw-r--r--core/tests/coretests/src/android/print/IPrintManagerParametersTest.java669
-rw-r--r--core/tests/coretests/src/android/print/PrintTestActivity.java33
-rw-r--r--core/tests/coretests/src/android/print/mockservice/MockPrintService.java40
-rw-r--r--core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java39
-rw-r--r--core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java50
-rw-r--r--core/tests/coretests/src/android/print/mockservice/SettingsActivity.java28
-rw-r--r--core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java52
-rw-r--r--core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java92
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java3
-rw-r--r--packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java3
-rw-r--r--services/print/java/com/android/server/print/PrintManagerService.java54
-rw-r--r--services/print/java/com/android/server/print/RemotePrintService.java6
-rw-r--r--services/print/java/com/android/server/print/UserState.java91
21 files changed, 1545 insertions, 63 deletions
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 3eb487461e5c..58f260cbe1cf 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -535,7 +535,10 @@ public final class PrintManager {
return new PrinterDiscoverySession(mService, mContext, mUserId);
}
- private static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
+ /**
+ * @hide
+ */
+ public static final class PrintDocumentAdapterDelegate extends IPrintDocumentAdapter.Stub
implements ActivityLifecycleCallbacks {
private final Object mLock = new Object();
@@ -1061,7 +1064,10 @@ public final class PrintManager {
}
}
- private static final class PrintJobStateChangeListenerWrapper extends
+ /**
+ * @hide
+ */
+ public static final class PrintJobStateChangeListenerWrapper extends
IPrintJobStateChangeListener.Stub {
private final WeakReference<PrintJobStateChangeListener> mWeakListener;
private final WeakReference<Handler> mWeakHandler;
diff --git a/core/java/android/print/PrinterDiscoverySession.java b/core/java/android/print/PrinterDiscoverySession.java
index abb441b79bc1..c587edde78f7 100644
--- a/core/java/android/print/PrinterDiscoverySession.java
+++ b/core/java/android/print/PrinterDiscoverySession.java
@@ -16,6 +16,8 @@
package android.print;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.os.Handler;
@@ -72,7 +74,7 @@ public final class PrinterDiscoverySession {
}
}
- public final void startPrinterDiscovery(List<PrinterId> priorityList) {
+ public final void startPrinterDiscovery(@Nullable List<PrinterId> priorityList) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring start printers discovery - session destroyed");
return;
@@ -102,7 +104,7 @@ public final class PrinterDiscoverySession {
}
}
- public final void startPrinterStateTracking(PrinterId printerId) {
+ public final void startPrinterStateTracking(@NonNull PrinterId printerId) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring start printer state tracking - session destroyed");
return;
@@ -114,7 +116,7 @@ public final class PrinterDiscoverySession {
}
}
- public final void stopPrinterStateTracking(PrinterId printerId) {
+ public final void stopPrinterStateTracking(@NonNull PrinterId printerId) {
if (isDestroyed()) {
Log.w(LOG_TAG, "Ignoring stop printer state tracking - session destroyed");
return;
@@ -285,7 +287,7 @@ public final class PrinterDiscoverySession {
}
}
- private static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
+ public static final class PrinterDiscoveryObserver extends IPrinterDiscoveryObserver.Stub {
private final WeakReference<PrinterDiscoverySession> mWeakSession;
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 310449222a0b..62d214e9e43c 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -16,6 +16,7 @@
package android.printservice;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Service;
import android.content.ComponentName;
@@ -346,7 +347,7 @@ public abstract class PrintService extends Service {
* @param localId A locally unique id in the context of your print service.
* @return Global printer id.
*/
- public final PrinterId generatePrinterId(String localId) {
+ public @NonNull final PrinterId generatePrinterId(String localId) {
throwIfNotCalledOnMainThread();
localId = Preconditions.checkNotNull(localId, "localId cannot be null");
return new PrinterId(new ComponentName(getPackageName(),
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 381e71f7f333..2f26e921d03b 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -42,6 +42,23 @@ public class Preconditions {
* @return the string reference that was validated
* @throws IllegalArgumentException if {@code string} is empty
*/
+ public static @NonNull String checkStringNotEmpty(final String string) {
+ if (TextUtils.isEmpty(string)) {
+ throw new IllegalArgumentException();
+ }
+ return string;
+ }
+
+ /**
+ * Ensures that an string reference passed as a parameter to the calling
+ * method is not empty.
+ *
+ * @param string an string reference
+ * @param errorMessage the exception message to use if the check fails; will
+ * be converted to a string using {@link String#valueOf(Object)}
+ * @return the string reference that was validated
+ * @throws IllegalArgumentException if {@code string} is empty
+ */
public static @NonNull String checkStringNotEmpty(final String string,
final Object errorMessage) {
if (TextUtils.isEmpty(string)) {
@@ -301,8 +318,8 @@ public class Preconditions {
*
* @throws NullPointerException if the {@code value} or any of its elements were {@code null}
*/
- public static <T> Collection<T> checkCollectionElementsNotNull(final Collection<T> value,
- final String valueName) {
+ public static @NonNull <C extends Collection<T>, T> C checkCollectionElementsNotNull(
+ final C value, final String valueName) {
if (value == null) {
throw new NullPointerException(valueName + " must not be null");
}
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index ee8921ef8228..eb055de01c63 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -32,7 +32,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
littlemock \
android-support-test \
mockito-target \
- espresso-core
+ espresso-core \
+ ub-uiautomator
LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy
LOCAL_PACKAGE_NAME := FrameworksCoreTests
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index eb0075b6b0b7..bfa2b10fdf4f 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1295,6 +1295,26 @@
</intent-filter>
</activity>
+ <activity android:name="android.print.PrintTestActivity"/>
+
+ <service
+ android:name="android.print.mockservice.MockPrintService"
+ android:permission="android.permission.BIND_PRINT_SERVICE">
+ <intent-filter>
+ <action android:name="android.printservice.PrintService" />
+ </intent-filter>
+ <meta-data
+ android:name="android.printservice"
+ android:resource="@xml/printservice">
+ </meta-data>
+ </service>
+
+ <activity
+ android:name="android.print.mockservice.SettingsActivity"
+ android:permission="android.permission.START_PRINT_SERVICE_CONFIG_ACTIVITY"
+ android:exported="true">
+ </activity>
+
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/core/tests/coretests/res/xml/printservice.xml b/core/tests/coretests/res/xml/printservice.xml
new file mode 100644
index 000000000000..abbebdae0d57
--- /dev/null
+++ b/core/tests/coretests/res/xml/printservice.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<print-service xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="android.print.mockservice.SettingsActivity"/>
diff --git a/core/tests/coretests/src/android/print/BasePrintTest.java b/core/tests/coretests/src/android/print/BasePrintTest.java
new file mode 100644
index 000000000000..19ce44a90815
--- /dev/null
+++ b/core/tests/coretests/src/android/print/BasePrintTest.java
@@ -0,0 +1,361 @@
+/*
+ * 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 static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.ParcelFileDescriptor;
+import android.os.SystemClock;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintManager;
+import android.print.PrinterId;
+import android.print.mockservice.PrintServiceCallbacks;
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.test.InstrumentationTestCase;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+
+import org.mockito.stubbing.Answer;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * This is the base class for print tests.
+ */
+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 ";
+ private static final String COMMAND_PREFIX_DISABLE_IME = "ime disable ";
+ private static final int CURRENT_USER_ID = -2; // Mirrors UserHandle.USER_CURRENT
+
+ private PrintTestActivity mActivity;
+ private android.print.PrintJob mPrintJob;
+
+ private LocaleList mOldLocale;
+
+ private CallCounter mStartCallCounter;
+ private CallCounter mStartSessionCallCounter;
+
+ private String[] mEnabledImes;
+
+ private String[] getEnabledImes() throws IOException {
+ List<String> imeList = new ArrayList<>();
+
+ ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+ .executeShellCommand(COMMAND_LIST_ENABLED_IME_COMPONENTS);
+ try (BufferedReader reader = new BufferedReader(
+ new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) {
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ imeList.add(line);
+ }
+ }
+
+ String[] imeArray = new String[imeList.size()];
+ imeList.toArray(imeArray);
+
+ return imeArray;
+ }
+
+ private void disableImes() throws Exception {
+ mEnabledImes = getEnabledImes();
+ for (String ime : mEnabledImes) {
+ String disableImeCommand = COMMAND_PREFIX_DISABLE_IME + ime;
+ runShellCommand(getInstrumentation(), disableImeCommand);
+ }
+ }
+
+ private void enableImes() throws Exception {
+ for (String ime : mEnabledImes) {
+ String enableImeCommand = COMMAND_PREFIX_ENABLE_IME + ime;
+ runShellCommand(getInstrumentation(), enableImeCommand);
+ }
+ mEnabledImes = null;
+ }
+
+ @Override
+ protected void runTest() throws Throwable {
+ // Do nothing if the device does not support printing.
+ if (supportsPrinting()) {
+ super.runTest();
+ }
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ // Make sure we start with a clean slate.
+ clearPrintSpoolerData();
+ disableImes();
+
+ // Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
+ // Dexmaker is used by mockito.
+ System.setProperty("dexmaker.dexcache", getInstrumentation()
+ .getTargetContext().getCacheDir().getPath());
+
+ // Set to US locale.
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ Configuration oldConfiguration = resources.getConfiguration();
+ if (!oldConfiguration.getLocales().getPrimary().equals(Locale.US)) {
+ mOldLocale = oldConfiguration.getLocales();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(oldConfiguration);
+ newConfiguration.setLocale(Locale.US);
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Initialize the latches.
+ mStartCallCounter = new CallCounter();
+ mStartSessionCallCounter = new CallCounter();
+
+ // Create the activity for the right locale.
+ createActivity();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ // Done with the activity.
+ getActivity().finish();
+ enableImes();
+
+ // Restore the locale if needed.
+ if (mOldLocale != null) {
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(resources.getConfiguration());
+ newConfiguration.setLocales(mOldLocale);
+ mOldLocale = null;
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Make sure the spooler is cleaned, this also un-approves all services
+ clearPrintSpoolerData();
+
+ super.tearDown();
+ }
+
+ protected android.print.PrintJob print(@NonNull final PrintDocumentAdapter adapter,
+ final PrintAttributes attributes) {
+ // Initiate printing as if coming from the app.
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ PrintManager printManager = (PrintManager) getActivity()
+ .getSystemService(Context.PRINT_SERVICE);
+ mPrintJob = printManager.print("Print job", adapter, attributes);
+ }
+ });
+
+ return mPrintJob;
+ }
+
+ protected void onStartCalled() {
+ mStartCallCounter.call();
+ }
+
+ protected void onPrinterDiscoverySessionStartCalled() {
+ mStartSessionCallCounter.call();
+ }
+
+ protected void waitForPrinterDiscoverySessionStartCallbackCalled() {
+ waitForCallbackCallCount(mStartSessionCallCounter, 1,
+ "Did not get expected call to onStartPrinterDiscoverySession.");
+ }
+
+ protected void waitForStartAdapterCallbackCalled() {
+ waitForCallbackCallCount(mStartCallCounter, 1, "Did not get expected call to start.");
+ }
+
+ private void waitForCallbackCallCount(CallCounter counter, int count, String message) {
+ try {
+ counter.waitForCount(count, OPERATION_TIMEOUT);
+ } catch (TimeoutException te) {
+ fail(message);
+ }
+ }
+
+ protected PrintTestActivity getActivity() {
+ return mActivity;
+ }
+
+ protected void createActivity() {
+ mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+ PrintTestActivity.class, null);
+ }
+
+ public static String runShellCommand(Instrumentation instrumentation, String cmd)
+ throws IOException {
+ ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
+ byte[] buf = new byte[512];
+ int bytesRead;
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ StringBuffer stdout = new StringBuffer();
+ while ((bytesRead = fis.read(buf)) != -1) {
+ stdout.append(new String(buf, 0, bytesRead));
+ }
+ fis.close();
+ return stdout.toString();
+ }
+
+ 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));
+ }
+
+ @SuppressWarnings("unchecked")
+ protected PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+ Answer<Void> onStartPrinterDiscovery, Answer<Void> onStopPrinterDiscovery,
+ Answer<Void> onValidatePrinters, Answer<Void> onStartPrinterStateTracking,
+ Answer<Void> onRequestCustomPrinterIcon, Answer<Void> onStopPrinterStateTracking,
+ Answer<Void> onDestroy) {
+ PrinterDiscoverySessionCallbacks callbacks = mock(PrinterDiscoverySessionCallbacks.class);
+
+ doCallRealMethod().when(callbacks).setSession(any(StubbablePrinterDiscoverySession.class));
+ when(callbacks.getSession()).thenCallRealMethod();
+
+ if (onStartPrinterDiscovery != null) {
+ doAnswer(onStartPrinterDiscovery).when(callbacks).onStartPrinterDiscovery(
+ any(List.class));
+ }
+ if (onStopPrinterDiscovery != null) {
+ doAnswer(onStopPrinterDiscovery).when(callbacks).onStopPrinterDiscovery();
+ }
+ if (onValidatePrinters != null) {
+ doAnswer(onValidatePrinters).when(callbacks).onValidatePrinters(
+ any(List.class));
+ }
+ if (onStartPrinterStateTracking != null) {
+ doAnswer(onStartPrinterStateTracking).when(callbacks).onStartPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onRequestCustomPrinterIcon != null) {
+ doAnswer(onRequestCustomPrinterIcon).when(callbacks).onRequestCustomPrinterIcon(
+ any(PrinterId.class), any(CustomPrinterIconCallback.class));
+ }
+ if (onStopPrinterStateTracking != null) {
+ doAnswer(onStopPrinterStateTracking).when(callbacks).onStopPrinterStateTracking(
+ any(PrinterId.class));
+ }
+ if (onDestroy != null) {
+ doAnswer(onDestroy).when(callbacks).onDestroy();
+ }
+
+ return callbacks;
+ }
+
+ protected PrintServiceCallbacks createMockPrintServiceCallbacks(
+ Answer<PrinterDiscoverySessionCallbacks> onCreatePrinterDiscoverySessionCallbacks,
+ Answer<Void> onPrintJobQueued, Answer<Void> onRequestCancelPrintJob) {
+ final PrintServiceCallbacks service = mock(PrintServiceCallbacks.class);
+
+ doCallRealMethod().when(service).setService(any(PrintService.class));
+ when(service.getService()).thenCallRealMethod();
+
+ if (onCreatePrinterDiscoverySessionCallbacks != null) {
+ doAnswer(onCreatePrinterDiscoverySessionCallbacks).when(service)
+ .onCreatePrinterDiscoverySessionCallbacks();
+ }
+ if (onPrintJobQueued != null) {
+ doAnswer(onPrintJobQueued).when(service).onPrintJobQueued(any(PrintJob.class));
+ }
+ if (onRequestCancelPrintJob != null) {
+ doAnswer(onRequestCancelPrintJob).when(service).onRequestCancelPrintJob(
+ any(PrintJob.class));
+ }
+
+ return service;
+ }
+
+ protected final class CallCounter {
+ private final Object mLock = new Object();
+
+ private int mCallCount;
+
+ public void call() {
+ synchronized (mLock) {
+ mCallCount++;
+ mLock.notifyAll();
+ }
+ }
+
+ public int getCallCount() {
+ synchronized (mLock) {
+ return mCallCount;
+ }
+ }
+
+ public void waitForCount(int count, long timeoutMillis) throws TimeoutException {
+ synchronized (mLock) {
+ final long startTimeMillis = SystemClock.uptimeMillis();
+ while (mCallCount < count) {
+ try {
+ final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+ final long remainingTimeMillis = timeoutMillis - elapsedTimeMillis;
+ if (remainingTimeMillis <= 0) {
+ throw new TimeoutException();
+ }
+ mLock.wait(timeoutMillis);
+ } catch (InterruptedException ie) {
+ /* ignore */
+ }
+ }
+ }
+ }
+ }
+
+ protected boolean supportsPrinting() {
+ return getInstrumentation().getContext().getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_PRINTING);
+ }
+}
diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
new file mode 100644
index 000000000000..5179b42fd650
--- /dev/null
+++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java
@@ -0,0 +1,669 @@
+/*
+ * 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.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+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;
+import android.print.mockservice.PrintServiceCallbacks;
+import android.print.mockservice.PrinterDiscoverySessionCallbacks;
+import android.print.mockservice.StubbablePrinterDiscoverySession;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * tests feeding all possible parameters to the IPrintManager Binder.
+ */
+public class IPrintManagerParametersTest extends BasePrintTest {
+
+ private final int BAD_APP_ID = 0xffffffff;
+
+ private final int mAppId;
+ private final int mUserId;
+ private final PrintJobId mBadPrintJobId;
+
+ private PrintJob mGoodPrintJob;
+ private PrinterId mBadPrinterId;
+ private PrinterId mGoodPrinterId;
+ private ComponentName mGoodComponentName;
+ private ComponentName mBadComponentName;
+
+ private IPrintManager mIPrintManager;
+
+ /**
+ * Create a new IPrintManagerParametersTest and setup basic fields.
+ */
+ public IPrintManagerParametersTest() {
+ super();
+
+ mAppId = UserHandle.getAppId(Process.myUid());
+ mUserId = UserHandle.myUserId();
+ mBadPrintJobId = new PrintJobId();
+ mBadComponentName = new ComponentName("bad", "bad");
+ }
+
+ /**
+ * Create a mock PrintDocumentAdapter.
+ *
+ * @return The adapter
+ */
+ private @NonNull PrintDocumentAdapter createMockAdapter() {
+ return new PrintDocumentAdapter() {
+ @Override
+ public void onStart() {
+ onStartCalled();
+ }
+
+ @Override
+ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
+ CancellationSignal cancellationSignal, LayoutResultCallback callback,
+ Bundle extras) {
+ }
+
+ @Override
+ public void onWrite(PageRange[] pages, ParcelFileDescriptor destination,
+ CancellationSignal cancellationSignal, WriteResultCallback callback) {
+ }
+ };
+ }
+
+ /**
+ * Create mock print service callbacks.
+ *
+ * @return the callbacks
+ */
+ private PrintServiceCallbacks createMockCallbacks() {
+ return createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ // Get the session.
+ StubbablePrinterDiscoverySession session =
+ ((PrinterDiscoverySessionCallbacks) invocation
+ .getMock()).getSession();
+
+ if (session.getPrinters().isEmpty()) {
+ final String PRINTER_NAME = "good printer";
+ List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+ // Add the printer.
+ mGoodPrinterId = session.getService()
+ .generatePrinterId(PRINTER_NAME);
+
+ PrinterCapabilitiesInfo capabilities =
+ new PrinterCapabilitiesInfo.Builder(mGoodPrinterId)
+ .setMinMargins(
+ new Margins(200, 200, 200, 200))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(new Resolution("300x300",
+ "300x300", 300, 300),
+ true)
+ .setColorModes(
+ PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+
+ PrinterInfo printer = new PrinterInfo.Builder(
+ mGoodPrinterId,
+ PRINTER_NAME,
+ PrinterInfo.STATUS_IDLE)
+ .setCapabilities(capabilities)
+ .build();
+ printers.add(printer);
+
+ session.addPrinters(printers);
+ }
+ onPrinterDiscoverySessionStartCalled();
+ return null;
+ }
+ }, null, null, null, null, null, null);
+ }
+ },
+ null, null);
+ }
+
+ /**
+ * Create a IPrintJobStateChangeListener object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IPrintJobStateChangeListener createMockIPrintJobStateChangeListener() throws Exception {
+ return new PrintManager.PrintJobStateChangeListenerWrapper(null,
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Create a IPrinterDiscoveryObserver object.
+ *
+ * @return the object
+ * @throws Exception if the object could not be created.
+ */
+ private IPrinterDiscoveryObserver createMockIPrinterDiscoveryObserver() throws Exception {
+ return new PrinterDiscoverySession.PrinterDiscoveryObserver(null);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ MockPrintService.setCallbacks(createMockCallbacks());
+
+ 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();
+ }
+
+ /**
+ * {@link Runnable} that can throw and {@link Exception}
+ */
+ private interface Invokable {
+ /**
+ * Execute the {@link Invokable}
+ *
+ * @throws Exception
+ */
+ public void run() throws Exception;
+ }
+
+ /**
+ * Assert that the invokable throws an expectedException
+ *
+ * @param invokable The {@link Invokable} to run
+ * @param expectedClass The {@link Exception} that is supposed to be thrown
+ */
+ public void assertException(Invokable invokable, Class<? extends Exception> expectedClass)
+ throws Exception {
+ try {
+ invokable.run();
+ } catch (Exception e) {
+ if (e.getClass().isAssignableFrom(expectedClass)) {
+ return;
+ } else {
+ throw new AssertionError("Expected: " + expectedClass.getName() + ", got: "
+ + e.getClass().getName());
+ }
+ }
+
+ throw new AssertionError("No exception thrown");
+ }
+
+ /**
+ * test IPrintManager.getPrintJobInfo
+ */
+ public void testGetPrintJobInfo() throws Exception {
+ assertEquals(mGoodPrintJob.getId(), mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(),
+ mAppId, mUserId).getId());
+ assertEquals(null, mIPrintManager.getPrintJobInfo(mBadPrintJobId, mAppId, mUserId));
+ assertEquals(null, mIPrintManager.getPrintJobInfo(null, mAppId, mUserId));
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getPrintJobInfo(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getPrintJobInfos
+ */
+ public void testGetPrintJobInfos() throws Exception {
+ List<PrintJobInfo> infos = mIPrintManager.getPrintJobInfos(mAppId, mUserId);
+
+ boolean foundPrintJob = false;
+ for (PrintJobInfo info : infos) {
+ if (info.getId().equals(mGoodPrintJob.getId())) {
+ assertEquals(PrintJobInfo.STATE_CREATED, info.getState());
+ foundPrintJob = true;
+ }
+ }
+ assertTrue(foundPrintJob);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getPrintJobInfos(BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.print
+ */
+ public void testPrint() throws Exception {
+ final String name = "dummy print job";
+
+ final IPrintDocumentAdapter adapter = new PrintManager
+ .PrintDocumentAdapterDelegate(getActivity(), createMockAdapter());
+
+ // Valid parameters are tested in setUp()
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(null, adapter, null, mGoodComponentName.getPackageName(),
+ mAppId, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, null, null, mGoodComponentName.getPackageName(),
+ mAppId, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, adapter, null, null, mAppId, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, adapter, null, mBadComponentName.getPackageName(),
+ mAppId, mUserId);
+ }
+ }, IllegalArgumentException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.print(name, adapter, null, mGoodComponentName.getPackageName(),
+ BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.cancelPrintJob
+ */
+ public void testCancelPrintJob() throws Exception {
+ // Invalid print jobs IDs do not produce an exception
+ mIPrintManager.cancelPrintJob(mBadPrintJobId, mAppId, mUserId);
+ mIPrintManager.cancelPrintJob(null, mAppId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+
+ // Must be last as otherwise mGoodPrintJob will not be good anymore
+ mIPrintManager.cancelPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+ }
+
+ /**
+ * test IPrintManager.restartPrintJob
+ */
+ public void testRestartPrintJob() throws Exception {
+ mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), mAppId, mUserId);
+
+ // Invalid print jobs IDs do not produce an exception
+ mIPrintManager.restartPrintJob(mBadPrintJobId, mAppId, mUserId);
+ mIPrintManager.restartPrintJob(null, mAppId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.restartPrintJob(mGoodPrintJob.getId(), BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.addPrintJobStateChangeListener
+ */
+ public void testAddPrintJobStateChangeListener() throws Exception {
+ final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
+
+ mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintJobStateChangeListener(null, mAppId, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.addPrintJobStateChangeListener(listener, BAD_APP_ID, mUserId);
+ }
+ }, SecurityException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.removePrintJobStateChangeListener
+ */
+ public void testRemovePrintJobStateChangeListener() throws Exception {
+ final IPrintJobStateChangeListener listener = createMockIPrintJobStateChangeListener();
+
+ mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+ mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
+
+ // Removing unknown listeners is a no-op
+ mIPrintManager.removePrintJobStateChangeListener(listener, mUserId);
+
+ mIPrintManager.addPrintJobStateChangeListener(listener, mAppId, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.removePrintJobStateChangeListener(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getInstalledPrintServices
+ */
+ public void testGetInstalledPrintServices() throws Exception {
+ List<PrintServiceInfo> printServices = mIPrintManager.getInstalledPrintServices(mUserId);
+ assertTrue(printServices.size() >= 2);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getEnabledPrintServices
+ */
+ public void testGetEnabledPrintServices() throws Exception {
+ List<PrintServiceInfo> printServices = mIPrintManager.getEnabledPrintServices(mUserId);
+ assertTrue(printServices.size() >= 2);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.createPrinterDiscoverySession
+ */
+ public void testCreatePrinterDiscoverySession() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+ mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
+
+ try {
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.createPrinterDiscoverySession(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ } finally {
+ // Remove discovery session so that the next test create a new one. Usually a leaked
+ // session is removed on the next call from the print service. But in this case we want
+ // to force a new call to onPrinterDiscoverySessionStart in the next test.
+ mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+ }
+ }
+
+ /**
+ * test IPrintManager.startPrinterDiscovery
+ */
+ public void testStartPrinterDiscovery() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+ final List<PrinterId> goodPrinters = new ArrayList<>();
+ goodPrinters.add(mGoodPrinterId);
+
+ final List<PrinterId> badPrinters = new ArrayList<>();
+ badPrinters.add(mBadPrinterId);
+
+ final List<PrinterId> emptyPrinters = new ArrayList<>();
+
+ final List<PrinterId> nullPrinters = new ArrayList<>();
+ nullPrinters.add(null);
+
+ mIPrintManager.startPrinterDiscovery(listener, goodPrinters, mUserId);
+
+ // Bad or no printers do no cause exceptions
+ mIPrintManager.startPrinterDiscovery(listener, badPrinters, mUserId);
+ mIPrintManager.startPrinterDiscovery(listener, emptyPrinters, mUserId);
+ mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.startPrinterDiscovery(listener, nullPrinters, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.startPrinterDiscovery(null, goodPrinters, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.stopPrinterDiscovery
+ */
+ public void testStopPrinterDiscovery() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+ mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+ mIPrintManager.stopPrinterDiscovery(listener, mUserId);
+
+ // Stopping an already stopped session is a no-op
+ mIPrintManager.stopPrinterDiscovery(listener, mUserId);
+
+ mIPrintManager.startPrinterDiscovery(listener, null, mUserId);
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.stopPrinterDiscovery(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.validatePrinters
+ */
+ public void testValidatePrinters() throws Exception {
+ final List<PrinterId> goodPrinters = new ArrayList<>();
+ goodPrinters.add(mGoodPrinterId);
+
+ final List<PrinterId> badPrinters = new ArrayList<>();
+ badPrinters.add(mBadPrinterId);
+
+ final List<PrinterId> emptyPrinters = new ArrayList<>();
+
+ final List<PrinterId> nullPrinters = new ArrayList<>();
+ nullPrinters.add(null);
+
+ mIPrintManager.validatePrinters(goodPrinters, mUserId);
+
+ // Bad or empty list of printers do no cause exceptions
+ mIPrintManager.validatePrinters(badPrinters, mUserId);
+ mIPrintManager.validatePrinters(emptyPrinters, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.validatePrinters(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.validatePrinters(nullPrinters, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.startPrinterStateTracking
+ */
+ public void testStartPrinterStateTracking() throws Exception {
+ mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
+
+ // Bad printers do no cause exceptions
+ mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.startPrinterStateTracking(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.getCustomPrinterIcon
+ */
+ public void testGetCustomPrinterIcon() throws Exception {
+ mIPrintManager.getCustomPrinterIcon(mGoodPrinterId, mUserId);
+
+ // Bad printers do no cause exceptions
+ mIPrintManager.getCustomPrinterIcon(mBadPrinterId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.getCustomPrinterIcon(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.stopPrinterStateTracking
+ */
+ public void testStopPrinterStateTracking() throws Exception {
+ mIPrintManager.startPrinterStateTracking(mGoodPrinterId, mUserId);
+ mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
+
+ // Stop to track a non-tracked printer is a no-op
+ mIPrintManager.stopPrinterStateTracking(mGoodPrinterId, mUserId);
+
+ // Bad printers do no cause exceptions
+ mIPrintManager.startPrinterStateTracking(mBadPrinterId, mUserId);
+ mIPrintManager.stopPrinterStateTracking(mBadPrinterId, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.stopPrinterStateTracking(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+
+ /**
+ * test IPrintManager.destroyPrinterDiscoverySession
+ */
+ public void testDestroyPrinterDiscoverySession() throws Exception {
+ final IPrinterDiscoveryObserver listener = createMockIPrinterDiscoveryObserver();
+
+ mIPrintManager.createPrinterDiscoverySession(listener, mUserId);
+ mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+
+ // Destroying already destroyed session is a no-op
+ mIPrintManager.destroyPrinterDiscoverySession(listener, mUserId);
+
+ assertException(new Invokable() {
+ @Override
+ public void run() throws Exception {
+ mIPrintManager.destroyPrinterDiscoverySession(null, mUserId);
+ }
+ }, NullPointerException.class);
+
+ // Cannot test bad user Id as these tests are allowed to call across users
+ }
+}
diff --git a/core/tests/coretests/src/android/print/PrintTestActivity.java b/core/tests/coretests/src/android/print/PrintTestActivity.java
new file mode 100644
index 000000000000..86074a62eab6
--- /dev/null
+++ b/core/tests/coretests/src/android/print/PrintTestActivity.java
@@ -0,0 +1,33 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class PrintTestActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/MockPrintService.java b/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
new file mode 100644
index 000000000000..9c11c22282d7
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/MockPrintService.java
@@ -0,0 +1,40 @@
+/*
+ * 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.mockservice;
+
+public class MockPrintService extends StubbablePrintService {
+
+ private static final Object sLock = new Object();
+
+ private static PrintServiceCallbacks sCallbacks;
+
+ public static void setCallbacks(PrintServiceCallbacks callbacks) {
+ synchronized (sLock) {
+ sCallbacks = callbacks;
+ }
+ }
+
+ @Override
+ protected PrintServiceCallbacks getCallbacks() {
+ synchronized (sLock) {
+ if (sCallbacks != null) {
+ sCallbacks.setService(this);
+ }
+ return sCallbacks;
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
new file mode 100644
index 000000000000..4e892072f0cb
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/PrintServiceCallbacks.java
@@ -0,0 +1,39 @@
+/*
+ * 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.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+
+public abstract class PrintServiceCallbacks {
+
+ private PrintService mService;
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ public void setService(PrintService service) {
+ mService = service;
+ }
+
+ public abstract PrinterDiscoverySessionCallbacks onCreatePrinterDiscoverySessionCallbacks();
+
+ public abstract void onRequestCancelPrintJob(PrintJob printJob);
+
+ public abstract void onPrintJobQueued(PrintJob printJob);
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
new file mode 100644
index 000000000000..26b7caeba15f
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/PrinterDiscoverySessionCallbacks.java
@@ -0,0 +1,50 @@
+/*
+ * 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.mockservice;
+
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+
+import java.util.List;
+
+public abstract class PrinterDiscoverySessionCallbacks {
+
+ private StubbablePrinterDiscoverySession mSession;
+
+ public void setSession(StubbablePrinterDiscoverySession session) {
+ mSession = session;
+ }
+
+ public StubbablePrinterDiscoverySession getSession() {
+ return mSession;
+ }
+
+ public abstract void onStartPrinterDiscovery(List<PrinterId> priorityList);
+
+ public abstract void onStopPrinterDiscovery();
+
+ public abstract void onValidatePrinters(List<PrinterId> printerIds);
+
+ public abstract void onStartPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onRequestCustomPrinterIcon(PrinterId printerId,
+ CustomPrinterIconCallback callback);
+
+ public abstract void onStopPrinterStateTracking(PrinterId printerId);
+
+ public abstract void onDestroy();
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java b/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
new file mode 100644
index 000000000000..fb76e6780374
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/SettingsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * 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.mockservice;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class SettingsActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
new file mode 100644
index 000000000000..b58b27350c28
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrintService.java
@@ -0,0 +1,52 @@
+/*
+ * 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.mockservice;
+
+import android.printservice.PrintJob;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+public abstract class StubbablePrintService extends PrintService {
+
+ @Override
+ public PrinterDiscoverySession onCreatePrinterDiscoverySession() {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ return new StubbablePrinterDiscoverySession(this,
+ getCallbacks().onCreatePrinterDiscoverySessionCallbacks());
+ }
+ return null;
+ }
+
+ @Override
+ public void onRequestCancelPrintJob(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onRequestCancelPrintJob(printJob);
+ }
+ }
+
+ @Override
+ public void onPrintJobQueued(PrintJob printJob) {
+ PrintServiceCallbacks callbacks = getCallbacks();
+ if (callbacks != null) {
+ callbacks.onPrintJobQueued(printJob);
+ }
+ }
+
+ protected abstract PrintServiceCallbacks getCallbacks();
+}
diff --git a/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
new file mode 100644
index 000000000000..04683f267aab
--- /dev/null
+++ b/core/tests/coretests/src/android/print/mockservice/StubbablePrinterDiscoverySession.java
@@ -0,0 +1,92 @@
+/*
+ * 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.mockservice;
+
+import android.print.PrinterId;
+import android.printservice.CustomPrinterIconCallback;
+import android.printservice.PrintService;
+import android.printservice.PrinterDiscoverySession;
+
+import java.util.List;
+
+public class StubbablePrinterDiscoverySession extends PrinterDiscoverySession {
+ private final PrintService mService;
+ private final PrinterDiscoverySessionCallbacks mCallbacks;
+
+ public StubbablePrinterDiscoverySession(PrintService service,
+ PrinterDiscoverySessionCallbacks callbacks) {
+ mService = service;
+ mCallbacks = callbacks;
+ if (mCallbacks != null) {
+ mCallbacks.setSession(this);
+ }
+ }
+
+ public PrintService getService() {
+ return mService;
+ }
+
+ @Override
+ public void onStartPrinterDiscovery(List<PrinterId> priorityList) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterDiscovery(priorityList);
+ }
+ }
+
+ @Override
+ public void onStopPrinterDiscovery() {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterDiscovery();
+ }
+ }
+
+ @Override
+ public void onValidatePrinters(List<PrinterId> printerIds) {
+ if (mCallbacks != null) {
+ mCallbacks.onValidatePrinters(printerIds);
+ }
+ }
+
+ @Override
+ public void onStartPrinterStateTracking(PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStartPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onRequestCustomPrinterIcon(PrinterId printerId,
+ CustomPrinterIconCallback callback) {
+ if (mCallbacks != null) {
+ mCallbacks.onRequestCustomPrinterIcon(printerId, callback);
+ }
+ }
+
+ @Override
+ public void onStopPrinterStateTracking(PrinterId printerId) {
+ if (mCallbacks != null) {
+ mCallbacks.onStopPrinterStateTracking(printerId);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mCallbacks != null) {
+ mCallbacks.onDestroy();
+ }
+ }
+}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
index cd30e263a65d..46a2098ad5da 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java
@@ -16,6 +16,7 @@
package com.android.printspooler.ui;
+import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
import android.content.Loader;
@@ -452,7 +453,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>>
return mPersistenceManager.mReadHistoryCompleted;
}
- public void setTrackedPrinter(PrinterId printerId) {
+ public void setTrackedPrinter(@Nullable PrinterId printerId) {
if (isStarted() && mDiscoverySession != null
&& mDiscoverySession.isPrinterDiscoveryStarted()) {
if (mTrackedPrinter != null) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
index cbc568ae1e11..6d60bb86cd7e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrinterRegistry.java
@@ -16,6 +16,7 @@
package com.android.printspooler.ui;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Loader;
@@ -89,7 +90,7 @@ public class PrinterRegistry {
return false;
}
- public void setTrackedPrinter(PrinterId printerId) {
+ public void setTrackedPrinter(@Nullable PrinterId printerId) {
FusedPrintersProvider provider = getPrinterProvider();
if (provider != null) {
provider.setTrackedPrinter(printerId);
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index 5abb6e7d9367..e6f41775111c 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
import android.Manifest;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.content.ComponentName;
@@ -47,11 +48,11 @@ import android.print.PrintJobInfo;
import android.print.PrinterId;
import android.printservice.PrintServiceInfo;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.SparseArray;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import java.io.FileDescriptor;
@@ -108,6 +109,10 @@ public final class PrintManagerService extends SystemService {
@Override
public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
PrintAttributes attributes, String packageName, int appId, int userId) {
+ printJobName = Preconditions.checkStringNotEmpty(printJobName);
+ adapter = Preconditions.checkNotNull(adapter);
+ packageName = Preconditions.checkStringNotEmpty(packageName);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -153,6 +158,10 @@ public final class PrintManagerService extends SystemService {
@Override
public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId, int userId) {
+ if (printJobId == null) {
+ return null;
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -174,6 +183,8 @@ public final class PrintManagerService extends SystemService {
@Override
public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
+ printerId = Preconditions.checkNotNull(printerId);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -193,6 +204,10 @@ public final class PrintManagerService extends SystemService {
@Override
public void cancelPrintJob(PrintJobId printJobId, int appId, int userId) {
+ if (printJobId == null) {
+ return;
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -214,6 +229,10 @@ public final class PrintManagerService extends SystemService {
@Override
public void restartPrintJob(PrintJobId printJobId, int appId, int userId) {
+ if (printJobId == null) {
+ return;
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -279,6 +298,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
+ observer = Preconditions.checkNotNull(observer);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -299,6 +320,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
int userId) {
+ observer = Preconditions.checkNotNull(observer);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -319,6 +342,12 @@ public final class PrintManagerService extends SystemService {
@Override
public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
List<PrinterId> priorityList, int userId) {
+ observer = Preconditions.checkNotNull(observer);
+ if (priorityList != null) {
+ priorityList = Preconditions.checkCollectionElementsNotNull(priorityList,
+ "PrinterId");
+ }
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -338,6 +367,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
+ observer = Preconditions.checkNotNull(observer);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -357,6 +388,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void validatePrinters(List<PrinterId> printerIds, int userId) {
+ printerIds = Preconditions.checkCollectionElementsNotNull(printerIds, "PrinterId");
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -376,6 +409,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void startPrinterStateTracking(PrinterId printerId, int userId) {
+ printerId = Preconditions.checkNotNull(printerId);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -395,6 +430,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void stopPrinterStateTracking(PrinterId printerId, int userId) {
+ printerId = Preconditions.checkNotNull(printerId);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -415,6 +452,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int appId, int userId) throws RemoteException {
+ listener = Preconditions.checkNotNull(listener);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final int resolvedAppId;
final UserState userState;
@@ -437,6 +476,8 @@ public final class PrintManagerService extends SystemService {
@Override
public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
int userId) {
+ listener = Preconditions.checkNotNull(listener);
+
final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
final UserState userState;
synchronized (mLock) {
@@ -456,6 +497,9 @@ public final class PrintManagerService extends SystemService {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ fd = Preconditions.checkNotNull(fd);
+ pw = Preconditions.checkNotNull(pw);
+
if (mContext.checkCallingOrSelfPermission(Manifest.permission.DUMP)
!= PackageManager.PERMISSION_GRANTED) {
pw.println("Permission Denial: can't dump PrintManager from from pid="
@@ -707,10 +751,8 @@ public final class PrintManagerService extends SystemService {
return userId;
}
- private String resolveCallingPackageNameEnforcingSecurity(String packageName) {
- if (TextUtils.isEmpty(packageName)) {
- return null;
- }
+ private @NonNull String resolveCallingPackageNameEnforcingSecurity(
+ @NonNull String packageName) {
String[] packages = mContext.getPackageManager().getPackagesForUid(
Binder.getCallingUid());
final int packageCount = packages.length;
@@ -719,7 +761,7 @@ public final class PrintManagerService extends SystemService {
return packageName;
}
}
- return null;
+ throw new IllegalArgumentException("packageName has to belong to the caller");
}
private int getCurrentUserId () {
diff --git a/services/print/java/com/android/server/print/RemotePrintService.java b/services/print/java/com/android/server/print/RemotePrintService.java
index 5ee4066f69ec..9b99c677a822 100644
--- a/services/print/java/com/android/server/print/RemotePrintService.java
+++ b/services/print/java/com/android/server/print/RemotePrintService.java
@@ -409,7 +409,7 @@ final class RemotePrintService implements DeathRecipient {
}
}
- public void startPrinterStateTracking(PrinterId printerId) {
+ public void startPrinterStateTracking(@NonNull PrinterId printerId) {
mHandler.obtainMessage(MyHandler.MSG_START_PRINTER_STATE_TRACKING,
printerId).sendToTarget();
}
@@ -420,7 +420,7 @@ final class RemotePrintService implements DeathRecipient {
* @param printerId the id of the printer the icon should be loaded for
* @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
*/
- public void requestCustomPrinterIcon(PrinterId printerId) {
+ public void requestCustomPrinterIcon(@NonNull PrinterId printerId) {
try {
if (isBound()) {
mPrintService.requestCustomPrinterIcon(printerId);
@@ -430,7 +430,7 @@ final class RemotePrintService implements DeathRecipient {
}
}
- private void handleStartPrinterStateTracking(final PrinterId printerId) {
+ private void handleStartPrinterStateTracking(final @NonNull PrinterId printerId) {
throwIfDestroyed();
// Take a note we are tracking the printer.
if (mTrackedPrinterList == null) {
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 78edc4df08fa..fcf2fc8e7860 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.GET_META_DATA;
import static android.content.pm.PackageManager.GET_SERVICES;
import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
@@ -176,8 +177,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
@SuppressWarnings("deprecation")
- public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
- PrintAttributes attributes, String packageName, int appId) {
+ public Bundle print(@NonNull String printJobName, @NonNull IPrintDocumentAdapter adapter,
+ @Nullable PrintAttributes attributes, @NonNull String packageName, int appId) {
// Create print job place holder.
final PrintJobInfo printJob = new PrintJobInfo();
printJob.setId(new PrintJobId());
@@ -267,7 +268,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
return new ArrayList<PrintJobInfo>(result.values());
}
- public PrintJobInfo getPrintJobInfo(PrintJobId printJobId, int appId) {
+ public PrintJobInfo getPrintJobInfo(@NonNull PrintJobId printJobId, int appId) {
PrintJobInfo printJob = mPrintJobForAppCache.getPrintJob(printJobId, appId);
if (printJob == null) {
printJob = mSpooler.getPrintJobInfo(printJobId, appId);
@@ -290,7 +291,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
* not yet available
* @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
*/
- public Icon getCustomPrinterIcon(PrinterId printerId) {
+ public @Nullable Icon getCustomPrinterIcon(@NonNull PrinterId printerId) {
Icon icon = mSpooler.getCustomPrinterIcon(printerId);
if (icon == null) {
@@ -303,7 +304,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
return icon;
}
- public void cancelPrintJob(PrintJobId printJobId, int appId) {
+ public void cancelPrintJob(@NonNull PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = mSpooler.getPrintJobInfo(printJobId, appId);
if (printJobInfo == null) {
return;
@@ -313,15 +314,19 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
mSpooler.setPrintJobCancelling(printJobId, true);
if (printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
- ComponentName printServiceName = printJobInfo.getPrinterId().getServiceName();
- RemotePrintService printService = null;
- synchronized (mLock) {
- printService = mActiveServices.get(printServiceName);
- }
- if (printService == null) {
- return;
+ PrinterId printerId = printJobInfo.getPrinterId();
+
+ if (printerId != null) {
+ ComponentName printServiceName = printerId.getServiceName();
+ RemotePrintService printService = null;
+ synchronized (mLock) {
+ printService = mActiveServices.get(printServiceName);
+ }
+ if (printService == null) {
+ return;
+ }
+ printService.onRequestCancelPrintJob(printJobInfo);
}
- printService.onRequestCancelPrintJob(printJobInfo);
} else {
// If the print job is failed we do not need cooperation
// from the print service.
@@ -329,7 +334,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void restartPrintJob(PrintJobId printJobId, int appId) {
+ public void restartPrintJob(@NonNull PrintJobId printJobId, int appId) {
PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId);
if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) {
return;
@@ -363,7 +368,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+ public void createPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -386,7 +391,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer) {
+ public void destroyPrinterDiscoverySession(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
// Already destroyed - nothing to do.
if (mPrinterDiscoverySession == null) {
@@ -397,8 +402,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
- List<PrinterId> printerIds) {
+ public void startPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer,
+ @Nullable List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -415,7 +420,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer) {
+ public void stopPrinterDiscovery(@NonNull IPrinterDiscoveryObserver observer) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -431,7 +436,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void validatePrinters(List<PrinterId> printerIds) {
+ public void validatePrinters(@NonNull List<PrinterId> printerIds) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -447,7 +452,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void startPrinterStateTracking(PrinterId printerId) {
+ public void startPrinterStateTracking(@NonNull PrinterId printerId) {
synchronized (mLock) {
throwIfDestroyedLocked();
// No services - nothing to do.
@@ -479,7 +484,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
+ public void addPrintJobStateChangeListener(@NonNull IPrintJobStateChangeListener listener,
int appId) throws RemoteException {
synchronized (mLock) {
throwIfDestroyedLocked();
@@ -497,7 +502,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener) {
+ public void removePrintJobStateChangeListener(@NonNull IPrintJobStateChangeListener listener) {
synchronized (mLock) {
throwIfDestroyedLocked();
if (mPrintJobStateChangeListenerRecords == null) {
@@ -613,7 +618,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
mDestroyed = true;
}
- public void dump(FileDescriptor fd, PrintWriter pw, String prefix) {
+ public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String prefix) {
pw.append(prefix).append("user state ").append(String.valueOf(mUserId)).append(":");
pw.println();
@@ -991,10 +996,10 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
private abstract class PrintJobStateChangeListenerRecord implements DeathRecipient {
- final IPrintJobStateChangeListener listener;
+ @NonNull final IPrintJobStateChangeListener listener;
final int appId;
- public PrintJobStateChangeListenerRecord(IPrintJobStateChangeListener listener,
+ public PrintJobStateChangeListenerRecord(@NonNull IPrintJobStateChangeListener listener,
int appId) throws RemoteException {
this.listener = listener;
this.appId = appId;
@@ -1043,7 +1048,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
.sendToTarget();
}
- public void addObserverLocked(IPrinterDiscoveryObserver observer) {
+ public void addObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
// Add the observer.
mDiscoveryObservers.register(observer);
@@ -1058,7 +1063,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public void removeObserverLocked(IPrinterDiscoveryObserver observer) {
+ public void removeObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
// Remove the observer.
mDiscoveryObservers.unregister(observer);
// No one else observing - then kill it.
@@ -1067,8 +1072,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public final void startPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer,
- List<PrinterId> priorityList) {
+ public final void startPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer,
+ @Nullable List<PrinterId> priorityList) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not starting dicovery - session destroyed");
return;
@@ -1101,7 +1106,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
.sendToTarget();
}
- public final void stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver observer) {
+ public final void stopPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not stopping dicovery - session destroyed");
return;
@@ -1121,7 +1126,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
.sendToTarget();
}
- public void validatePrintersLocked(List<PrinterId> printerIds) {
+ public void validatePrintersLocked(@NonNull List<PrinterId> printerIds) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not validating pritners - session destroyed");
return;
@@ -1135,13 +1140,15 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
ComponentName serviceName = null;
while (iterator.hasNext()) {
PrinterId printerId = iterator.next();
- if (updateList.isEmpty()) {
- updateList.add(printerId);
- serviceName = printerId.getServiceName();
- iterator.remove();
- } else if (printerId.getServiceName().equals(serviceName)) {
- updateList.add(printerId);
- iterator.remove();
+ if (printerId != null) {
+ if (updateList.isEmpty()) {
+ updateList.add(printerId);
+ serviceName = printerId.getServiceName();
+ iterator.remove();
+ } else if (printerId.getServiceName().equals(serviceName)) {
+ updateList.add(printerId);
+ iterator.remove();
+ }
}
}
// Schedule a notification of the service.
@@ -1157,7 +1164,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
}
}
- public final void startPrinterStateTrackingLocked(PrinterId printerId) {
+ public final void startPrinterStateTrackingLocked(@NonNull PrinterId printerId) {
if (mIsDestroyed) {
Log.w(LOG_TAG, "Not starting printer state tracking - session destroyed");
return;
@@ -1500,8 +1507,8 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks {
service.validatePrinters(printerIds);
}
- private void handleStartPrinterStateTracking(RemotePrintService service,
- PrinterId printerId) {
+ private void handleStartPrinterStateTracking(@NonNull RemotePrintService service,
+ @NonNull PrinterId printerId) {
service.startPrinterStateTracking(printerId);
}