summaryrefslogtreecommitdiff
path: root/core/java
diff options
context:
space:
mode:
authorPhilip P. Moltmann <moltmann@google.com>2016-03-31 01:33:15 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2016-03-31 01:33:17 +0000
commit740a5f023eea7b2fdb3e31efe8b8d5ac18aa8302 (patch)
treefd1f11d0a5173e59bd8451d633b87ad6bc1a40ec /core/java
parentbc2294b3c2503105c37d8de4a8cd825189199868 (diff)
parent9dcb86a48d73f399fb1b5c020005d76d350eeac2 (diff)
Merge "Add the print service recommendation service" into nyc-dev
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/print/IPrintManager.aidl34
-rw-r--r--core/java/android/print/PrintManager.java156
-rw-r--r--core/java/android/print/PrintServiceRecommendationsLoader.java121
-rw-r--r--core/java/android/print/PrintServicesLoader.java10
-rw-r--r--core/java/android/printservice/recommendation/IRecommendationService.aidl30
-rw-r--r--core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl35
-rw-r--r--core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl26
-rw-r--r--core/java/android/printservice/recommendation/RecommendationInfo.aidl22
-rw-r--r--core/java/android/printservice/recommendation/RecommendationInfo.java133
-rw-r--r--core/java/android/printservice/recommendation/RecommendationService.java138
-rw-r--r--core/java/com/android/internal/util/Preconditions.java26
11 files changed, 719 insertions, 12 deletions
diff --git a/core/java/android/print/IPrintManager.aidl b/core/java/android/print/IPrintManager.aidl
index 5eb8cc2f37a4..d7c267b5ca63 100644
--- a/core/java/android/print/IPrintManager.aidl
+++ b/core/java/android/print/IPrintManager.aidl
@@ -24,9 +24,11 @@ import android.print.IPrintDocumentAdapter;
import android.print.PrintJobId;
import android.print.IPrintJobStateChangeListener;
import android.print.IPrintServicesChangeListener;
+import android.printservice.recommendation.IRecommendationsChangeListener;
import android.print.PrinterId;
import android.print.PrintJobInfo;
import android.print.PrintAttributes;
+import android.printservice.recommendation.RecommendationInfo;
import android.printservice.PrintServiceInfo;
/**
@@ -73,7 +75,6 @@ interface IPrintManager {
* 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.
@@ -89,6 +90,37 @@ interface IPrintManager {
*/
void setPrintServiceEnabled(in ComponentName service, boolean isEnabled, int userId);
+ /**
+ * Listen for changes to the print service recommendations.
+ *
+ * @param listener the listener to add
+ * @param userId the id of the user listening
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void addPrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+ int userId);
+
+ /**
+ * Stop listening for changes to the print service recommendations.
+ *
+ * @param listener the listener to remove
+ * @param userId the id of the user requesting the removal
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void removePrintServiceRecommendationsChangeListener(in IRecommendationsChangeListener listener,
+ int userId);
+
+ /**
+ * Get the print service recommendations.
+ *
+ * @param userId the id of the user requesting the recommendations
+ *
+ * @return the list of selected print services.
+ */
+ List<RecommendationInfo> getPrintServiceRecommendations(int userId);
+
void createPrinterDiscoverySession(in IPrinterDiscoveryObserver observer, int userId);
void startPrinterDiscovery(in IPrinterDiscoveryObserver observer,
in List<PrinterId> priorityList, int userId);
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 25fc968fec5a..71f0bd615206 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -36,12 +36,15 @@ import android.os.RemoteException;
import android.print.PrintDocumentAdapter.LayoutResultCallback;
import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.printservice.PrintServiceInfo;
+import android.printservice.recommendation.IRecommendationsChangeListener;
+import android.printservice.recommendation.RecommendationInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
import java.lang.ref.WeakReference;
@@ -113,6 +116,7 @@ public final class PrintManager {
private static final int MSG_NOTIFY_PRINT_JOB_STATE_CHANGED = 1;
private static final int MSG_NOTIFY_PRINT_SERVICES_CHANGED = 2;
+ private static final int MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED = 3;
/**
* Package name of print spooler.
@@ -202,6 +206,9 @@ public final class PrintManager {
mPrintJobStateChangeListeners;
private Map<PrintServicesChangeListener, PrintServicesChangeListenerWrapper>
mPrintServicesChangeListeners;
+ private Map<PrintServiceRecommendationsChangeListener,
+ PrintServiceRecommendationsChangeListenerWrapper>
+ mPrintServiceRecommendationsChangeListeners;
/** @hide */
public interface PrintJobStateChangeListener {
@@ -223,6 +230,15 @@ public final class PrintManager {
public void onPrintServicesChanged();
}
+ /** @hide */
+ public interface PrintServiceRecommendationsChangeListener {
+
+ /**
+ * Callback notifying that the print service recommendations changed.
+ */
+ void onPrintServiceRecommendationsChanged();
+ }
+
/**
* Creates a new instance.
*
@@ -260,7 +276,14 @@ public final class PrintManager {
listener.onPrintServicesChanged();
}
} break;
-
+ case MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED: {
+ PrintServiceRecommendationsChangeListenerWrapper wrapper =
+ (PrintServiceRecommendationsChangeListenerWrapper) message.obj;
+ PrintServiceRecommendationsChangeListener listener = wrapper.getListener();
+ if (listener != null) {
+ listener.onPrintServiceRecommendationsChanged();
+ }
+ } break;
}
}
};
@@ -539,13 +562,14 @@ public final class PrintManager {
* @see android.print.PrintManager#getPrintServices
*/
void addPrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return;
}
if (mPrintServicesChangeListeners == null) {
- mPrintServicesChangeListeners = new ArrayMap<PrintServicesChangeListener,
- PrintServicesChangeListenerWrapper>();
+ mPrintServicesChangeListeners = new ArrayMap<>();
}
PrintServicesChangeListenerWrapper wrappedListener =
new PrintServicesChangeListenerWrapper(listener, mHandler);
@@ -565,6 +589,8 @@ public final class PrintManager {
* @see android.print.PrintManager#getPrintServices
*/
void removePrintServicesChangeListener(@NonNull PrintServicesChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
if (mService == null) {
Log.w(LOG_TAG, "Feature android.software.print not available");
return;
@@ -588,7 +614,6 @@ public final class PrintManager {
}
}
-
/**
* 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}.
@@ -596,7 +621,7 @@ public final class PrintManager {
* @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.
+ * @return The print service list or an empty list.
*
* @see #addPrintServicesChangeListener(PrintServicesChangeListener)
* @see #removePrintServicesChangeListener(PrintServicesChangeListener)
@@ -604,6 +629,8 @@ public final class PrintManager {
* @hide
*/
public @NonNull List<PrintServiceInfo> getPrintServices(int selectionFlags) {
+ Preconditions.checkFlagsArgument(selectionFlags, ALL_SERVICES);
+
try {
List<PrintServiceInfo> services = mService.getPrintServices(selectionFlags, mUserId);
if (services != null) {
@@ -616,6 +643,92 @@ public final class PrintManager {
}
/**
+ * Listen for changes to the print service recommendations.
+ *
+ * @param listener the listener to add
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void addPrintServiceRecommendationsChangeListener(
+ @NonNull PrintServiceRecommendationsChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
+ if (mPrintServiceRecommendationsChangeListeners == null) {
+ mPrintServiceRecommendationsChangeListeners = new ArrayMap<>();
+ }
+ PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+ new PrintServiceRecommendationsChangeListenerWrapper(listener, mHandler);
+ try {
+ mService.addPrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+ mPrintServiceRecommendationsChangeListeners.put(listener, wrappedListener);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Stop listening for changes to the print service recommendations.
+ *
+ * @param listener the listener to remove
+ *
+ * @see android.print.PrintManager#getPrintServiceRecommendations
+ */
+ void removePrintServiceRecommendationsChangeListener(
+ @NonNull PrintServiceRecommendationsChangeListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ if (mService == null) {
+ Log.w(LOG_TAG, "Feature android.software.print not available");
+ return;
+ }
+ if (mPrintServiceRecommendationsChangeListeners == null) {
+ return;
+ }
+ PrintServiceRecommendationsChangeListenerWrapper wrappedListener =
+ mPrintServiceRecommendationsChangeListeners.remove(listener);
+ if (wrappedListener == null) {
+ return;
+ }
+ if (mPrintServiceRecommendationsChangeListeners.isEmpty()) {
+ mPrintServiceRecommendationsChangeListeners = null;
+ }
+ wrappedListener.destroy();
+ try {
+ mService.removePrintServiceRecommendationsChangeListener(wrappedListener, mUserId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the list of print service recommendations, but does not register for updates. The user
+ * has to register for updates by itself, or use {@link PrintServiceRecommendationsLoader}.
+ *
+ * @return The print service recommendations list or an empty list.
+ *
+ * @see #addPrintServiceRecommendationsChangeListener
+ * @see #removePrintServiceRecommendationsChangeListener
+ *
+ * @hide
+ */
+ public @NonNull List<RecommendationInfo> getPrintServiceRecommendations() {
+ try {
+ List<RecommendationInfo> recommendations =
+ mService.getPrintServiceRecommendations(mUserId);
+ if (recommendations != null) {
+ return recommendations;
+ }
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ return Collections.emptyList();
+ }
+
+ /**
* @hide
*/
public PrinterDiscoverySession createPrinterDiscoverySession() {
@@ -1242,4 +1355,37 @@ public final class PrintManager {
return mWeakListener.get();
}
}
+
+ /**
+ * @hide
+ */
+ public static final class PrintServiceRecommendationsChangeListenerWrapper extends
+ IRecommendationsChangeListener.Stub {
+ private final WeakReference<PrintServiceRecommendationsChangeListener> mWeakListener;
+ private final WeakReference<Handler> mWeakHandler;
+
+ public PrintServiceRecommendationsChangeListenerWrapper(
+ PrintServiceRecommendationsChangeListener listener, Handler handler) {
+ mWeakListener = new WeakReference<>(listener);
+ mWeakHandler = new WeakReference<>(handler);
+ }
+
+ @Override
+ public void onRecommendationsChanged() {
+ Handler handler = mWeakHandler.get();
+ PrintServiceRecommendationsChangeListener listener = mWeakListener.get();
+ if (handler != null && listener != null) {
+ handler.obtainMessage(MSG_NOTIFY_PRINT_SERVICE_RECOMMENDATIONS_CHANGED,
+ this).sendToTarget();
+ }
+ }
+
+ public void destroy() {
+ mWeakListener.clear();
+ }
+
+ public PrintServiceRecommendationsChangeListener getListener() {
+ return mWeakListener.get();
+ }
+ }
}
diff --git a/core/java/android/print/PrintServiceRecommendationsLoader.java b/core/java/android/print/PrintServiceRecommendationsLoader.java
new file mode 100644
index 000000000000..bb5d065c6430
--- /dev/null
+++ b/core/java/android/print/PrintServiceRecommendationsLoader.java
@@ -0,0 +1,121 @@
+/*
+ * 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.recommendation.RecommendationInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+
+/**
+ * Loader for the list of print service recommendations.
+ *
+ * @hide
+ */
+public class PrintServiceRecommendationsLoader extends Loader<List<RecommendationInfo>> {
+ /** 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 final Handler mHandler;
+
+ /** Listens for updates to the data from the platform */
+ private PrintManager.PrintServiceRecommendationsChangeListener mListener;
+
+ /**
+ * Create a new PrintServicesLoader.
+ *
+ * @param printManager The print manager supplying the data
+ * @param context Context of the using object
+ */
+ public PrintServiceRecommendationsLoader(@NonNull PrintManager printManager,
+ @NonNull Context context) {
+ super(Preconditions.checkNotNull(context));
+ mHandler = new MyHandler();
+ mPrintManager = Preconditions.checkNotNull(printManager);
+ }
+
+ @Override
+ protected void onForceLoad() {
+ queueNewResult();
+ }
+
+ /**
+ * Read the print service recommendations and queue it to be delivered on the main thread.
+ */
+ private void queueNewResult() {
+ Message m = mHandler.obtainMessage(0);
+ m.obj = mPrintManager.getPrintServiceRecommendations();
+ mHandler.sendMessage(m);
+ }
+
+ @Override
+ protected void onStartLoading() {
+ mListener = new PrintManager.PrintServiceRecommendationsChangeListener() {
+ @Override
+ public void onPrintServiceRecommendationsChanged() {
+ queueNewResult();
+ }
+ };
+
+ mPrintManager.addPrintServiceRecommendationsChangeListener(mListener);
+
+ // Immediately deliver a result
+ deliverResult(mPrintManager.getPrintServiceRecommendations());
+ }
+
+ @Override
+ protected void onStopLoading() {
+ if (mListener != null) {
+ mPrintManager.removePrintServiceRecommendationsChangeListener(mListener);
+ mListener = null;
+ }
+
+ if (mHandler != null) {
+ mHandler.removeMessages(0);
+ }
+ }
+
+ @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) {
+ if (isStarted()) {
+ deliverResult((List<RecommendationInfo>) msg.obj);
+ }
+ }
+ }
+}
diff --git a/core/java/android/print/PrintServicesLoader.java b/core/java/android/print/PrintServicesLoader.java
index ed411141d1fb..60d7d666c2c9 100644
--- a/core/java/android/print/PrintServicesLoader.java
+++ b/core/java/android/print/PrintServicesLoader.java
@@ -22,6 +22,7 @@ import android.content.Loader;
import android.os.Handler;
import android.os.Message;
import android.printservice.PrintServiceInfo;
+import com.android.internal.util.Preconditions;
import java.util.List;
@@ -46,13 +47,16 @@ public class PrintServicesLoader extends Loader<List<PrintServiceInfo>> {
/**
* Create a new PrintServicesLoader.
*
+ * @param printManager The print manager supplying the data
+ * @param context Context of the using object
* @param selectionFlags What type of services to load.
*/
public PrintServicesLoader(@NonNull PrintManager printManager, @NonNull Context context,
int selectionFlags) {
- super(context);
- mPrintManager = printManager;
- mSelectionFlags = selectionFlags;
+ super(Preconditions.checkNotNull(context));
+ mPrintManager = Preconditions.checkNotNull(printManager);
+ mSelectionFlags = Preconditions.checkFlagsArgument(selectionFlags,
+ PrintManager.ALL_SERVICES);
}
@Override
diff --git a/core/java/android/printservice/recommendation/IRecommendationService.aidl b/core/java/android/printservice/recommendation/IRecommendationService.aidl
new file mode 100644
index 000000000000..ce9ea6fd9fcb
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationService.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.printservice.recommendation.IRecommendationServiceCallbacks;
+
+/**
+ * Interface for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationServiceCallbacks
+ *
+ * @hide
+ */
+oneway interface IRecommendationService {
+ void registerCallbacks(in IRecommendationServiceCallbacks callbacks);
+}
diff --git a/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
new file mode 100644
index 000000000000..95286544eed0
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationServiceCallbacks.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.printservice.recommendation.RecommendationInfo;
+
+/**
+ * Callbacks for communication with the print service recommendation service.
+ *
+ * @see android.print.IPrintServiceRecommendationService
+ *
+ * @hide
+ */
+oneway interface IRecommendationServiceCallbacks {
+ /**
+ * Update the print service recommendations.
+ *
+ * @param recommendations the new print service recommendations
+ */
+ void onRecommendationsUpdated(in List<RecommendationInfo> recommendations);
+}
diff --git a/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.aidl
new file mode 100644
index 000000000000..8ca5c69e8180
--- /dev/null
+++ b/core/java/android/printservice/recommendation/IRecommendationsChangeListener.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.printservice.recommendation;
+
+/**
+ * Interface for observing changes of the print service recommendations.
+ *
+ * @hide
+ */
+oneway interface IRecommendationsChangeListener {
+ void onRecommendationsChanged();
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.aidl b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
new file mode 100644
index 000000000000..f21d0bf3f584
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.aidl
@@ -0,0 +1,22 @@
+/**
+ * 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.printservice.recommendation;
+
+/**
+ * @hide
+ */
+parcelable RecommendationInfo;
diff --git a/core/java/android/printservice/recommendation/RecommendationInfo.java b/core/java/android/printservice/recommendation/RecommendationInfo.java
new file mode 100644
index 000000000000..65d534e45e1c
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationInfo.java
@@ -0,0 +1,133 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.printservice.PrintService;
+import com.android.internal.util.Preconditions;
+
+/**
+ * A recommendation to install a {@link PrintService print service}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RecommendationInfo implements Parcelable {
+ /** Package name of the print service. */
+ private @NonNull final CharSequence mPackageName;
+
+ /** Display name of the print service. */
+ private @NonNull final CharSequence mName;
+
+ /** Number of printers the print service would discover if installed. */
+ private @IntRange(from = 0) final int mNumDiscoveredPrinters;
+
+ /** If the service detects printer from multiple vendors. */
+ private final boolean mRecommendsMultiVendorService;
+
+ /**
+ * Create a new recommendation.
+ *
+ * @param packageName Package name of the print service
+ * @param name Display name of the print service
+ * @param numDiscoveredPrinters Number of printers the print service would discover if
+ * installed
+ * @param recommendsMultiVendorService If the service detects printer from multiple vendor
+ */
+ public RecommendationInfo(@NonNull CharSequence packageName, @NonNull CharSequence name,
+ @IntRange(from = 0) int numDiscoveredPrinters, boolean recommendsMultiVendorService) {
+ mPackageName = Preconditions.checkStringNotEmpty(packageName);
+ mName = Preconditions.checkStringNotEmpty(name);
+ mNumDiscoveredPrinters = Preconditions.checkArgumentNonnegative(numDiscoveredPrinters);
+ mRecommendsMultiVendorService = recommendsMultiVendorService;
+ }
+
+ /**
+ * Create a new recommendation from a parcel.
+ *
+ * @param parcel The parcel containing the data
+ *
+ * @see #CREATOR
+ */
+ private RecommendationInfo(@NonNull Parcel parcel) {
+ this(parcel.readCharSequence(), parcel.readCharSequence(), parcel.readInt(),
+ parcel.readByte() != 0);
+ }
+
+ /**
+ * @return The package name the recommendations recommends.
+ */
+ public CharSequence getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * @return Whether the recommended print service detects printers of more than one vendor.
+ */
+ public boolean recommendsMultiVendorService() {
+ return mRecommendsMultiVendorService;
+ }
+
+ /**
+ * @return The number of printer the print service would detect.
+ */
+ public int getNumDiscoveredPrinters() {
+ return mNumDiscoveredPrinters;
+ }
+
+ /**
+ * @return The name of the recommended print service.
+ */
+ public CharSequence getName() {
+ return mName;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeCharSequence(mPackageName);
+ dest.writeCharSequence(mName);
+ dest.writeInt(mNumDiscoveredPrinters);
+ dest.writeByte((byte) (mRecommendsMultiVendorService ? 1 : 0));
+ }
+
+ /**
+ * Utility class used to create new print service recommendation objects from parcels.
+ *
+ * @see #RecommendationInfo(Parcel)
+ */
+ public static final Creator<RecommendationInfo> CREATOR =
+ new Creator<RecommendationInfo>() {
+ @Override
+ public RecommendationInfo createFromParcel(Parcel in) {
+ return new RecommendationInfo(in);
+ }
+
+ @Override
+ public RecommendationInfo[] newArray(int size) {
+ return new RecommendationInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/printservice/recommendation/RecommendationService.java b/core/java/android/printservice/recommendation/RecommendationService.java
new file mode 100644
index 000000000000..b7ea51271043
--- /dev/null
+++ b/core/java/android/printservice/recommendation/RecommendationService.java
@@ -0,0 +1,138 @@
+/*
+ * 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.printservice.recommendation;
+
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.List;
+
+/**
+ * Base class for the print service recommendation services.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class RecommendationService extends Service {
+ private static final String LOG_TAG = "PrintServiceRecS";
+
+ /** Used to push onConnect and onDisconnect on the main thread */
+ private Handler mHandler;
+
+ /**
+ * The {@link Intent} action that must be declared as handled by a service in its manifest for
+ * the system to recognize it as a print service recommendation service.
+ *
+ * @hide
+ */
+ public static final String SERVICE_INTERFACE =
+ "android.printservice.recommendation.RecommendationService";
+
+ /** Registered callbacks, only modified on main thread */
+ private IRecommendationServiceCallbacks mCallbacks;
+
+ @Override
+ protected void attachBaseContext(Context base) {
+ super.attachBaseContext(base);
+
+ mHandler = new MyHandler();
+ }
+
+ /**
+ * Update the print service recommendations.
+ *
+ * @param recommendations The new set of recommendations
+ */
+ public final void updateRecommendations(@Nullable List<RecommendationInfo> recommendations) {
+ mHandler.obtainMessage(MyHandler.MSG_UPDATE, recommendations).sendToTarget();
+ }
+
+ @Override
+ public final IBinder onBind(Intent intent) {
+ return new IRecommendationService.Stub() {
+ @Override
+ public void registerCallbacks(IRecommendationServiceCallbacks callbacks) {
+ // The callbacks come in order of the caller on oneway calls. Hence while the caller
+ // cannot know at what time the connection is made, he can know the ordering of
+ // connection and disconnection.
+ //
+ // Similar he cannot know when the disconnection is processed, hence he has to
+ // handle callbacks after calling disconnect.
+ if (callbacks != null) {
+ mHandler.obtainMessage(MyHandler.MSG_CONNECT, callbacks).sendToTarget();
+ } else {
+ mHandler.obtainMessage(MyHandler.MSG_DISCONNECT).sendToTarget();
+ }
+ }
+ };
+ }
+
+ /**
+ * Called when the client connects to the recommendation service.
+ */
+ public abstract void onConnected();
+
+ /**
+ * Called when the client disconnects from the recommendation service.
+ */
+ public abstract void onDisconnected();
+
+ private class MyHandler extends Handler {
+ static final int MSG_CONNECT = 1;
+ static final int MSG_DISCONNECT = 2;
+ static final int MSG_UPDATE = 3;
+
+ MyHandler() {
+ super(Looper.getMainLooper());
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CONNECT:
+ mCallbacks = (IRecommendationServiceCallbacks) msg.obj;
+ onConnected();
+ break;
+ case MSG_DISCONNECT:
+ onDisconnected();
+ mCallbacks = null;
+ break;
+ case MSG_UPDATE:
+ // Note that there might be a connection change in progress. In this case the
+ // message is handled as before the change. This is acceptable as the caller of
+ // the connection change has not guarantee when the connection change binder
+ // transaction is actually processed.
+ try {
+ mCallbacks.onRecommendationsUpdated((List<RecommendationInfo>) msg.obj);
+ } catch (RemoteException | NullPointerException e) {
+ Log.e(LOG_TAG, "Could not update recommended services", e);
+ }
+ break;
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index c46851e1c757..7c8524671716 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -56,7 +56,7 @@ 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) {
+ public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string) {
if (TextUtils.isEmpty(string)) {
throw new IllegalArgumentException();
}
@@ -73,7 +73,7 @@ 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,
+ public static @NonNull <T extends CharSequence> T checkStringNotEmpty(final T string,
final Object errorMessage) {
if (TextUtils.isEmpty(string)) {
throw new IllegalArgumentException(String.valueOf(errorMessage));
@@ -141,13 +141,17 @@ public class Preconditions {
/**
* Check the requested flags, throwing if any requested flags are outside
* the allowed set.
+ *
+ * @return the validated requested flags.
*/
- public static void checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
+ public static int checkFlagsArgument(final int requestedFlags, final int allowedFlags) {
if ((requestedFlags & allowedFlags) != requestedFlags) {
throw new IllegalArgumentException("Requested flags 0x"
+ Integer.toHexString(requestedFlags) + ", but only 0x"
+ Integer.toHexString(allowedFlags) + " are allowed");
}
+
+ return requestedFlags;
}
/**
@@ -170,6 +174,22 @@ public class Preconditions {
/**
* Ensures that that the argument numeric value is non-negative.
*
+ * @param value a numeric int value
+ *
+ * @return the validated numeric value
+ * @throws IllegalArgumentException if {@code value} was negative
+ */
+ public static @IntRange(from = 0) int checkArgumentNonnegative(final int value) {
+ if (value < 0) {
+ throw new IllegalArgumentException();
+ }
+
+ return value;
+ }
+
+ /**
+ * Ensures that that the argument numeric value is non-negative.
+ *
* @param value a numeric long value
* @param errorMessage the exception message to use if the check fails
* @return the validated numeric value