blob: 26300b1e37b9d3b17be98ec2d8d4b852e15c7a5b [file] [log] [blame]
Philip P. Moltmann9dcb86a2016-03-14 14:31:12 -07001/*
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
17package com.android.printservice.recommendation.plugin.mdnsFilter;
18
19import android.annotation.NonNull;
20import android.annotation.Nullable;
21import android.annotation.StringRes;
22import android.content.Context;
23import android.net.nsd.NsdManager;
24import android.net.nsd.NsdServiceInfo;
25import android.util.Log;
26import com.android.internal.annotations.GuardedBy;
27import com.android.internal.util.Preconditions;
28import com.android.printservice.recommendation.PrintServicePlugin;
29import com.android.printservice.recommendation.util.MDNSUtils;
30import com.android.printservice.recommendation.util.NsdResolveQueue;
31
32import java.util.HashSet;
33import java.util.List;
34
35/**
36 * A plugin listening for mDNS results and only adding the ones that {@link
37 * MDNSUtils#isVendorPrinter match} configured list
38 */
39public class MDNSFilterPlugin implements PrintServicePlugin, NsdManager.DiscoveryListener {
40 private static final String LOG_TAG = "MDNSFilterPlugin";
41
42 private static final String PRINTER_SERVICE_TYPE = "_ipp._tcp";
43
44 /** Name of the print service this plugin is for */
45 private final @StringRes int mName;
46
47 /** Package name of the print service this plugin is for */
48 private final @NonNull CharSequence mPackageName;
49
50 /** mDNS names handled by the print service this plugin is for */
51 private final @NonNull HashSet<String> mMDNSNames;
52
53 /** Printer identifiers of the mPrinters found. */
54 @GuardedBy("mLock")
55 private final @NonNull HashSet<String> mPrinters;
56
57 /** Context of the user of this plugin */
58 private final @NonNull Context mContext;
59
60 /**
61 * Call back to report the number of mPrinters found.
62 *
63 * We assume that {@link #start} and {@link #stop} are never called in parallel, hence it is
64 * safe to not synchronize access to this field.
65 */
66 private @Nullable PrinterDiscoveryCallback mCallback;
67
68 /** Queue used to resolve nsd infos */
69 private final @NonNull NsdResolveQueue mResolveQueue;
70
71 /**
72 * Create new stub that assumes that a print service can be used to print on all mPrinters
73 * matching some mDNS names.
74 *
75 * @param context The context the plugin runs in
76 * @param name The user friendly name of the print service
77 * @param packageName The package name of the print service
78 * @param mDNSNames The mDNS names of the printer.
79 */
80 public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
81 @NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
82 mContext = Preconditions.checkNotNull(context, "context");
83 mName = mContext.getResources().getIdentifier(Preconditions.checkStringNotEmpty(name,
84 "name"), null, mContext.getPackageName());
85 mPackageName = Preconditions.checkStringNotEmpty(packageName);
86 mMDNSNames = new HashSet<>(Preconditions
87 .checkCollectionNotEmpty(Preconditions.checkCollectionElementsNotNull(mDNSNames,
88 "mDNSNames"), "mDNSNames"));
89
90 mResolveQueue = NsdResolveQueue.getInstance();
91 mPrinters = new HashSet<>();
92 }
93
94 @Override
95 public @NonNull CharSequence getPackageName() {
96 return mPackageName;
97 }
98
99 /**
100 * @return The NDS manager
101 */
102 private NsdManager getNDSManager() {
103 return (NsdManager) mContext.getSystemService(Context.NSD_SERVICE);
104 }
105
106 @Override
107 public void start(@NonNull PrinterDiscoveryCallback callback) throws Exception {
108 mCallback = callback;
109
110 getNDSManager().discoverServices(PRINTER_SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD,
111 this);
112 }
113
114 @Override
115 public @StringRes int getName() {
116 return mName;
117 }
118
119 @Override
120 public void stop() throws Exception {
121 mCallback.onChanged(0);
122 mCallback = null;
123
124 getNDSManager().stopServiceDiscovery(this);
125 }
126
127 @Override
128 public void onStartDiscoveryFailed(String serviceType, int errorCode) {
129 Log.w(LOG_TAG, "Failed to start network discovery for type " + serviceType + ": "
130 + errorCode);
131 }
132
133 @Override
134 public void onStopDiscoveryFailed(String serviceType, int errorCode) {
135 Log.w(LOG_TAG, "Failed to stop network discovery for type " + serviceType + ": "
136 + errorCode);
137 }
138
139 @Override
140 public void onDiscoveryStarted(String serviceType) {
141 // empty
142 }
143
144 @Override
145 public void onDiscoveryStopped(String serviceType) {
146 mPrinters.clear();
147 }
148
149 @Override
150 public void onServiceFound(NsdServiceInfo serviceInfo) {
151 mResolveQueue.resolve(getNDSManager(), serviceInfo,
152 new NsdManager.ResolveListener() {
153 @Override
154 public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
155 Log.w(LOG_TAG, "Service found: could not resolve " + serviceInfo + ": " +
156 errorCode);
157 }
158
159 @Override
160 public void onServiceResolved(NsdServiceInfo serviceInfo) {
161 if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
162 if (mCallback != null) {
163 boolean added = mPrinters.add(serviceInfo.getHost().getHostAddress());
164
165 if (added) {
166 mCallback.onChanged(mPrinters.size());
167 }
168 }
169 }
170 }
171 });
172 }
173
174 @Override
175 public void onServiceLost(NsdServiceInfo serviceInfo) {
176 mResolveQueue.resolve(getNDSManager(), serviceInfo,
177 new NsdManager.ResolveListener() {
178 @Override
179 public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
180 Log.w(LOG_TAG, "Service lost: Could not resolve " + serviceInfo + ": "
181 + errorCode);
182 }
183
184 @Override
185 public void onServiceResolved(NsdServiceInfo serviceInfo) {
186 if (MDNSUtils.isVendorPrinter(serviceInfo, mMDNSNames)) {
187 if (mCallback != null) {
188 boolean removed = mPrinters
189 .remove(serviceInfo.getHost().getHostAddress());
190
191 if (removed) {
192 mCallback.onChanged(mPrinters.size());
193 }
194 }
195 }
196 }
197 });
198 }
199}