1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * Copyright (C) 2016 Mopria Alliance, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bips.discovery; 19 20 import android.net.Uri; 21 import android.util.Log; 22 23 import com.android.bips.BuiltInPrintService; 24 25 import java.util.Collection; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Objects; 30 import java.util.concurrent.CopyOnWriteArrayList; 31 32 /** 33 * Parent class for all printer discovery mechanisms. Subclasses must implement onStart and onStop. 34 * While started, discovery mechanisms deliver DiscoveredPrinter objects via 35 * {@link #printerFound(DiscoveredPrinter)} when they appear, and {@link #printerLost(Uri)} when 36 * they become unavailable. 37 */ 38 public abstract class Discovery { 39 private static final String TAG = Discovery.class.getSimpleName(); 40 private static final boolean DEBUG = false; 41 42 private final BuiltInPrintService mPrintService; 43 private final List<Listener> mListeners = new CopyOnWriteArrayList<>(); 44 private final Map<Uri, DiscoveredPrinter> mPrinters = new HashMap<>(); 45 46 private boolean mStarted = false; 47 Discovery(BuiltInPrintService printService)48 Discovery(BuiltInPrintService printService) { 49 mPrintService = printService; 50 } 51 52 /** 53 * Add a listener and begin receiving notifications from the Discovery object of any 54 * printers it finds. 55 */ start(Listener listener)56 public void start(Listener listener) { 57 mListeners.add(listener); 58 mPrinters.values().forEach(listener::onPrinterFound); 59 start(); 60 } 61 62 /** 63 * Remove a listener so that it no longer receives notifications of found printers. 64 * Discovery will continue for other listeners until the last one is removed. 65 */ stop(Listener listener)66 public void stop(Listener listener) { 67 mListeners.remove(listener); 68 if (mListeners.isEmpty()) { 69 stop(); 70 } 71 } 72 73 /** 74 * Return true if this object is in a started state 75 */ isStarted()76 boolean isStarted() { 77 return mStarted; 78 } 79 80 /** 81 * Return the current print service instance 82 */ getPrintService()83 BuiltInPrintService getPrintService() { 84 return mPrintService; 85 } 86 87 /** 88 * Start if not already started 89 */ start()90 private void start() { 91 if (!mStarted) { 92 mStarted = true; 93 onStart(); 94 } 95 } 96 97 /** 98 * Stop if not already stopped 99 */ stop()100 private void stop() { 101 if (mStarted) { 102 mStarted = false; 103 onStop(); 104 mPrinters.clear(); 105 } 106 } 107 108 /** 109 * Start searching for printers 110 */ onStart()111 abstract void onStart(); 112 113 /** 114 * Stop searching for printers, freeing any search-reated resources. 115 */ onStop()116 abstract void onStop(); 117 118 /** 119 * Signal that a printer appeared or possibly changed state. 120 */ printerFound(DiscoveredPrinter printer)121 void printerFound(DiscoveredPrinter printer) { 122 DiscoveredPrinter current = mPrinters.get(printer.getUri()); 123 if (Objects.equals(current, printer)) { 124 if (DEBUG) Log.d(TAG, "Already have the reported printer, ignoring"); 125 return; 126 } 127 mPrinters.put(printer.getUri(), printer); 128 for (Listener listener : mListeners) { 129 listener.onPrinterFound(printer); 130 } 131 } 132 133 /** 134 * Signal that a printer is no longer visible 135 */ printerLost(Uri printerUri)136 void printerLost(Uri printerUri) { 137 DiscoveredPrinter printer = mPrinters.remove(printerUri); 138 if (printer == null) return; 139 for (Listener listener : mListeners) { 140 listener.onPrinterLost(printer); 141 } 142 } 143 144 /** Signal loss of all printers */ allPrintersLost()145 void allPrintersLost() { 146 for (DiscoveredPrinter printer : mPrinters.values()) { 147 for (Listener listener : mListeners) { 148 listener.onPrinterLost(printer); 149 } 150 } 151 mPrinters.clear(); 152 } 153 154 /** 155 * Return the working collection of currently-found printers 156 */ getPrinters()157 Collection<DiscoveredPrinter> getPrinters() { 158 return mPrinters.values(); 159 } 160 161 public interface Listener { onPrinterFound(DiscoveredPrinter printer)162 void onPrinterFound(DiscoveredPrinter printer); 163 onPrinterLost(DiscoveredPrinter printer)164 void onPrinterLost(DiscoveredPrinter printer); 165 } 166 }