1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.printservice.recommendation; 18 19 import androidx.annotation.NonNull; 20 import androidx.annotation.Nullable; 21 import androidx.annotation.StringRes; 22 23 import com.android.printservice.recommendation.util.Preconditions; 24 25 import java.net.InetAddress; 26 import java.util.Collections; 27 import java.util.List; 28 29 /** 30 * Wrapper for a {@link PrintServicePlugin}, isolating issues with the plugin as good as possible 31 * from the {@link RecommendationServiceImpl service}. 32 */ 33 class RemotePrintServicePlugin implements PrintServicePlugin.PrinterDiscoveryCallback { 34 /** Lock for this object */ 35 private final Object mLock = new Object(); 36 37 /** The name of the print service. */ 38 public final @StringRes int name; 39 40 /** If the print service if for more than a single vendor */ 41 public final boolean recommendsMultiVendorService; 42 43 /** The package name of the full print service */ 44 public final @NonNull CharSequence packageName; 45 46 /** Wrapped plugin */ 47 private final @NonNull PrintServicePlugin mPlugin; 48 49 /** The printers discovered by the plugin */ 50 private @NonNull List<InetAddress> mPrinters; 51 52 /** If the plugin is started by not yet stopped */ 53 private boolean isRunning; 54 55 /** Listener for changes to {@link #mPrinters}. */ 56 private @NonNull OnChangedListener mListener; 57 58 /** 59 * Create a new remote for a {@link PrintServicePlugin plugin}. 60 * 61 * @param plugin The plugin to be wrapped 62 * @param listener The listener to be notified about changes in this plugin 63 * @param recommendsMultiVendorService If the plugin detects printers of more than a single 64 * vendor 65 * 66 * @throws PluginException If the plugin has issues while caching basic stub properties 67 */ RemotePrintServicePlugin(@onNull PrintServicePlugin plugin, @NonNull OnChangedListener listener, boolean recommendsMultiVendorService)68 public RemotePrintServicePlugin(@NonNull PrintServicePlugin plugin, 69 @NonNull OnChangedListener listener, boolean recommendsMultiVendorService) 70 throws PluginException { 71 mListener = listener; 72 mPlugin = plugin; 73 mPrinters = Collections.emptyList(); 74 75 this.recommendsMultiVendorService = recommendsMultiVendorService; 76 77 // We handle any throwable to isolate our self from bugs in the plugin code. 78 // Cache simple properties to avoid having to deal with exceptions later in the code. 79 try { 80 name = Preconditions.checkArgumentPositive(mPlugin.getName(), "name"); 81 packageName = Preconditions.checkStringNotEmpty(mPlugin.getPackageName(), 82 "packageName"); 83 } catch (Throwable e) { 84 throw new PluginException(mPlugin, "Cannot cache simple properties ", e); 85 } 86 87 isRunning = false; 88 } 89 90 /** 91 * Start the plugin. From now on there might be callbacks to the registered listener. 92 */ start()93 public void start() 94 throws PluginException { 95 // We handle any throwable to isolate our self from bugs in the stub code 96 try { 97 synchronized (mLock) { 98 isRunning = true; 99 mPlugin.start(this); 100 } 101 } catch (Throwable e) { 102 throw new PluginException(mPlugin, "Cannot start", e); 103 } 104 } 105 106 /** 107 * Stop the plugin. From this call on there will not be any more callbacks. 108 */ stop()109 public void stop() throws PluginException { 110 // We handle any throwable to isolate our self from bugs in the stub code 111 try { 112 synchronized (mLock) { 113 mPlugin.stop(); 114 isRunning = false; 115 } 116 } catch (Throwable e) { 117 throw new PluginException(mPlugin, "Cannot stop", e); 118 } 119 } 120 121 /** 122 * Get the current number of printers reported by the stub. 123 * 124 * @return The number of printers reported by the stub. 125 */ getPrinters()126 public @NonNull List<InetAddress> getPrinters() { 127 return mPrinters; 128 } 129 130 @Override onChanged(@ullable List<InetAddress> discoveredPrinters)131 public void onChanged(@Nullable List<InetAddress> discoveredPrinters) { 132 synchronized (mLock) { 133 Preconditions.checkState(isRunning); 134 135 if (discoveredPrinters == null) { 136 mPrinters = Collections.emptyList(); 137 } else { 138 mPrinters = Preconditions.checkCollectionElementsNotNull(discoveredPrinters, 139 "discoveredPrinters"); 140 } 141 142 mListener.onChanged(); 143 } 144 } 145 146 /** 147 * Listener to listen for changes to {@link #getPrinters} 148 */ 149 public interface OnChangedListener { onChanged()150 void onChanged(); 151 } 152 153 /** 154 * Exception thrown if the stub has any issues. 155 */ 156 public class PluginException extends Exception { PluginException(PrintServicePlugin plugin, String message, Throwable e)157 private PluginException(PrintServicePlugin plugin, String message, Throwable e) { 158 super(plugin + ": " + message, e); 159 } 160 } 161 } 162