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 */
16package com.android.printservice.recommendation.plugin.xerox;
17
18import android.content.Context;
19import android.net.nsd.NsdManager;
20import android.net.nsd.NsdServiceInfo;
21import android.text.TextUtils;
22import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
23import com.android.printservice.recommendation.util.NsdResolveQueue;
24
25import java.util.ArrayList;
26import java.util.LinkedList;
27import java.util.List;
28
29class ServiceResolver {
30
31    private final NsdManager mNSDManager;
32    private final String[] mServiceType;
33    private final Observer mObserver;
34    private final VendorInfo mVendorInfo;
35    private final String[] mPDLs;
36    private final PrinterHashMap mPrinterHashMap = new PrinterHashMap();
37    private final List<NsdManager.DiscoveryListener> mListeners = new ArrayList<>();
38    private final NsdResolveQueue mNsdResolveQueue;
39
40    public interface Observer {
41        void dataSetChanged();
42    }
43
44    public ServiceResolver(Context context, Observer observer, VendorInfo vendorInfo, String[] serviceTypes, String[] pdls) {
45        mNsdResolveQueue = NsdResolveQueue.getInstance();
46        mObserver = observer;
47        mServiceType = serviceTypes;
48        mNSDManager = (NsdManager) context.getSystemService(Context.NSD_SERVICE);
49        mVendorInfo = vendorInfo;
50        mPDLs = pdls;
51    }
52
53    public void start() {
54        stop();
55        for (final String service : mServiceType) {
56            NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
57                @Override
58                public void onStartDiscoveryFailed(String s, int i) {
59
60                }
61
62                @Override
63                public void onStopDiscoveryFailed(String s, int i) {
64
65                }
66
67                @Override
68                public void onDiscoveryStarted(String s) {
69
70                }
71
72                @Override
73                public void onDiscoveryStopped(String s) {
74
75                }
76
77                @Override
78                public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
79                    queueRequest(nsdServiceInfo);
80                }
81
82                @Override
83                public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
84                    removeRequest(nsdServiceInfo);
85                    printerRemoved(nsdServiceInfo);
86                }
87            };
88            DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
89            mListeners.add(listener);
90        }
91    }
92
93    public void stop() {
94        for (NsdManager.DiscoveryListener listener : mListeners) {
95            DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
96        }
97        mListeners.clear();
98        clearRequests();
99    }
100
101    //Resolving nsd services
102    private final LinkedList<NsdServiceInfo> mQueue = new LinkedList<>();
103    private final Object mLock = new Object();
104    private NsdServiceInfo mCurrentRequest = null;
105
106    private void queueRequest(NsdServiceInfo serviceInfo) {
107        synchronized (mLock) {
108            if (mQueue.contains(serviceInfo)) return;
109            mQueue.add(serviceInfo);
110            makeNextRequest();
111        }
112    }
113
114    private void removeRequest(NsdServiceInfo serviceInfo) {
115        synchronized (mLock) {
116            mQueue.remove(serviceInfo);
117            if ((mCurrentRequest != null) && serviceInfo.equals(mCurrentRequest))
118                mCurrentRequest = null;
119        }
120    }
121
122    private void clearRequests() {
123        synchronized (mLock) {
124            mQueue.clear();
125        }
126    }
127
128    private void makeNextRequest() {
129        synchronized (mLock) {
130            if (mCurrentRequest != null) return;
131            if (mQueue.isEmpty()) return;
132            mCurrentRequest = mQueue.removeFirst();
133            mNsdResolveQueue.resolve(mNSDManager, mCurrentRequest, new NsdManager.ResolveListener() {
134                @Override
135                public void onResolveFailed(NsdServiceInfo nsdServiceInfo, int i) {
136                    synchronized (mLock) {
137                        if (mCurrentRequest != null) mQueue.add(mCurrentRequest);
138                        makeNextRequest();
139                    }
140                }
141
142                @Override
143                public void onServiceResolved(NsdServiceInfo nsdServiceInfo) {
144                    synchronized (mLock) {
145                        if (mCurrentRequest != null) {
146                            printerFound(nsdServiceInfo);
147                            mCurrentRequest = null;
148                        }
149                        makeNextRequest();
150                    }
151                }
152            });
153
154        }
155    }
156
157    private void printerFound(NsdServiceInfo nsdServiceInfo) {
158        if (nsdServiceInfo == null) return;
159        if (TextUtils.isEmpty(PrinterHashMap.getKey(nsdServiceInfo))) return;
160        String vendor = MDnsUtils.getVendor(nsdServiceInfo);
161        if (vendor == null) vendor = "";
162
163        for (String vendorValues : mVendorInfo.mDNSValues) {
164            if (vendor.equalsIgnoreCase(vendorValues)) {
165                vendor = mVendorInfo.mVendorID;
166                break;
167            }
168        }
169
170        if ((vendor != mVendorInfo.mVendorID) &&
171                MDnsUtils.isVendorPrinter(nsdServiceInfo, mVendorInfo.mDNSValues)) {
172            vendor = mVendorInfo.mVendorID;
173        }
174
175        if (!(vendor == mVendorInfo.mVendorID)) {
176            return;
177        }
178
179        if (!MDnsUtils.checkPDLSupport(nsdServiceInfo, mPDLs)) {
180            return;
181        }
182
183        if ((mPrinterHashMap.addPrinter(nsdServiceInfo) == null)) {
184            mObserver.dataSetChanged();
185        }
186
187    }
188
189    private void printerRemoved(NsdServiceInfo nsdServiceInfo) {
190        if ((mPrinterHashMap.removePrinter(nsdServiceInfo) != null)) {
191            mObserver.dataSetChanged();
192        }
193    }
194
195    public int getCount() {
196        return mPrinterHashMap.size();
197    }
198
199}
200