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 import androidx.core.util.Preconditions; 23 24 import java.net.InetAddress; 25 import java.util.Collections; 26 import java.util.List; 27 28 /** 29 * Wrapper for a {@link PrintServicePlugin}, isolating issues with the plugin as good as possible 30 * from the {@link RecommendationServiceImpl service}. 31 */ 32 class RemotePrintServicePlugin implements PrintServicePlugin.PrinterDiscoveryCallback { 33 /** Lock for this object */ 34 private final Object mLock = new Object(); 35 36 /** The name of the print service. */ 37 public final @StringRes int name; 38 39 /** If the print service if for more than a single vendor */ 40 public final boolean recommendsMultiVendorService; 41 42 /** The package name of the full print service */ 43 public final @NonNull CharSequence packageName; 44 45 /** Wrapped plugin */ 46 private final @NonNull PrintServicePlugin mPlugin; 47 48 /** The printers discovered by the plugin */ 49 private @NonNull List<InetAddress> mPrinters; 50 51 /** If the plugin is started by not yet stopped */ 52 private boolean isRunning; 53 54 /** Listener for changes to {@link #mPrinters}. */ 55 private @NonNull OnChangedListener mListener; 56 57 /** 58 * Create a new remote for a {@link PrintServicePlugin plugin}. 59 * 60 * @param plugin The plugin to be wrapped 61 * @param listener The listener to be notified about changes in this plugin 62 * @param recommendsMultiVendorService If the plugin detects printers of more than a single 63 * vendor 64 * 65 * @throws PluginException If the plugin has issues while caching basic stub properties 66 */ RemotePrintServicePlugin(@onNull PrintServicePlugin plugin, @NonNull OnChangedListener listener, boolean recommendsMultiVendorService)67 public RemotePrintServicePlugin(@NonNull PrintServicePlugin plugin, 68 @NonNull OnChangedListener listener, boolean recommendsMultiVendorService) 69 throws PluginException { 70 mListener = listener; 71 mPlugin = plugin; 72 mPrinters = Collections.emptyList(); 73 74 this.recommendsMultiVendorService = recommendsMultiVendorService; 75 76 // We handle any throwable to isolate our self from bugs in the plugin code. 77 // Cache simple properties to avoid having to deal with exceptions later in the code. 78 try { 79 name = Preconditions.checkArgumentPositive(mPlugin.getName(), "name"); 80 packageName = Preconditions.checkStringNotEmpty(mPlugin.getPackageName(), 81 "packageName"); 82 } catch (Throwable e) { 83 throw new PluginException(mPlugin, "Cannot cache simple properties ", e); 84 } 85 86 isRunning = false; 87 } 88 89 /** 90 * Start the plugin. From now on there might be callbacks to the registered listener. 91 */ start()92 public void start() 93 throws PluginException { 94 // We handle any throwable to isolate our self from bugs in the stub code 95 try { 96 synchronized (mLock) { 97 isRunning = true; 98 mPlugin.start(this); 99 } 100 } catch (Throwable e) { 101 throw new PluginException(mPlugin, "Cannot start", e); 102 } 103 } 104 105 /** 106 * Stop the plugin. From this call on there will not be any more callbacks. 107 */ stop()108 public void stop() throws PluginException { 109 // We handle any throwable to isolate our self from bugs in the stub code 110 try { 111 synchronized (mLock) { 112 mPlugin.stop(); 113 isRunning = false; 114 } 115 } catch (Throwable e) { 116 throw new PluginException(mPlugin, "Cannot stop", e); 117 } 118 } 119 120 /** 121 * Get the current number of printers reported by the stub. 122 * 123 * @return The number of printers reported by the stub. 124 */ getPrinters()125 public @NonNull List<InetAddress> getPrinters() { 126 return mPrinters; 127 } 128 129 @Override onChanged(@ullable List<InetAddress> discoveredPrinters)130 public void onChanged(@Nullable List<InetAddress> discoveredPrinters) { 131 synchronized (mLock) { 132 Preconditions.checkState(isRunning); 133 134 if (discoveredPrinters == null) { 135 mPrinters = Collections.emptyList(); 136 } else { 137 mPrinters = Preconditions.checkCollectionElementsNotNull(discoveredPrinters, 138 "discoveredPrinters"); 139 } 140 141 mListener.onChanged(); 142 } 143 } 144 145 /** 146 * Listener to listen for changes to {@link #getPrinters} 147 */ 148 public interface OnChangedListener { onChanged()149 void onChanged(); 150 } 151 152 /** 153 * Exception thrown if the stub has any issues. 154 */ 155 public class PluginException extends Exception { PluginException(PrintServicePlugin plugin, String message, Throwable e)156 private PluginException(PrintServicePlugin plugin, String message, Throwable e) { 157 super(plugin + ": " + message, e); 158 } 159 } 160 } 161