1bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann/*
2bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * Copyright (C) 2016 The Android Open Source Project
3bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann *
4bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * Licensed under the Apache License, Version 2.0 (the "License");
5bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * you may not use this file except in compliance with the License.
6bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * You may obtain a copy of the License at
7bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann *
8bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann *      http://www.apache.org/licenses/LICENSE-2.0
9bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann *
10bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * Unless required by applicable law or agreed to in writing, software
11bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * distributed under the License is distributed on an "AS IS" BASIS,
12bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * See the License for the specific language governing permissions and
14bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann * limitations under the License.
15bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann */
16bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
17bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannpackage com.android.printservice.recommendation.plugin.hp;
18bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
19bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport android.content.Context;
20bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport android.content.res.TypedArray;
21bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport android.net.nsd.NsdManager;
22bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport android.net.nsd.NsdServiceInfo;
23bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport android.text.TextUtils;
24bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport android.util.Pair;
25bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
26bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport java.util.ArrayList;
27bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport java.util.HashMap;
28bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport java.util.List;
29bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport java.util.Map;
30bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport java.util.Set;
31bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
32bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport com.android.printservice.recommendation.R;
33bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannimport com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
34bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
35bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmannpublic class ServiceListener implements ServiceResolveQueue.ResolveCallback {
36bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
37bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private final NsdManager mNSDManager;
38bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private final Map<String, VendorInfo> mVendorInfoHashMap;
39bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private final String[] mServiceType;
40bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private final Observer mObserver;
41bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private final ServiceResolveQueue mResolveQueue;
42bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private List<NsdManager.DiscoveryListener> mListeners = new ArrayList<>();
43bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public HashMap<String, PrinterHashMap> mVendorHashMap = new HashMap<>();
44bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
45bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public interface Observer {
46bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        boolean matchesCriteria(String vendor, NsdServiceInfo serviceInfo);
47bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        void dataSetChanged();
48bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
49bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
50bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public ServiceListener(Context context, Observer observer, String[] serviceTypes) {
51bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mObserver = observer;
52bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mServiceType = serviceTypes;
53bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mNSDManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
54bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mResolveQueue = ServiceResolveQueue.getInstance(mNSDManager);
55bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
56bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        Map<String, VendorInfo> vendorInfoMap = new HashMap<>();
57bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        TypedArray testArray = context.getResources().obtainTypedArray(R.array.known_print_plugin_vendors);
58bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        for(int i = 0; i < testArray.length(); i++) {
59bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            int arrayID = testArray.getResourceId(i, 0);
60bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            if (arrayID != 0) {
61bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                VendorInfo info = new VendorInfo(context.getResources(), arrayID);
62bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                vendorInfoMap.put(info.mVendorID, info);
63bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                vendorInfoMap.put(info.mPackageName, info);
64bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            }
65bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
66bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        testArray.recycle();
67bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mVendorInfoHashMap = vendorInfoMap;
68bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
69bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
70bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    @Override
71bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public void serviceResolved(NsdServiceInfo nsdServiceInfo) {
72bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        printerFound(nsdServiceInfo);
73bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
74bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
75bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private synchronized void printerFound(NsdServiceInfo nsdServiceInfo) {
76bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (nsdServiceInfo == null) return;
77bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (TextUtils.isEmpty(PrinterHashMap.getKey(nsdServiceInfo))) return;
78bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        String vendor = MDnsUtils.getVendor(nsdServiceInfo);
79bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (vendor == null) vendor = "";
80bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        for(Map.Entry<String,VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
81bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            for(String vendorValues : entry.getValue().mDNSValues) {
82bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                if (vendor.equalsIgnoreCase(vendorValues)) {
83bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                    vendor = entry.getValue().mVendorID;
84bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                    break;
85bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
86bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            }
87bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            // intentional pointer check
88bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            //noinspection StringEquality
89bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            if ((vendor != entry.getValue().mVendorID) &&
90bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                    MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
91bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                vendor = entry.getValue().mVendorID;
92bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            }
93bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            // intentional pointer check
94bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            //noinspection StringEquality
95bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            if (vendor == entry.getValue().mVendorID) break;
96bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
97bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
98bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (TextUtils.isEmpty(vendor)) {
99bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            return;
100bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
101bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
102bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
103bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            return;
104bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        boolean mapsChanged;
105bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
106bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
107bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (vendorHash == null) {
108bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            vendorHash = new PrinterHashMap();
109bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
110bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
111bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mVendorHashMap.put(vendor, vendorHash);
112bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
113bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (mapsChanged) {
114bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            mObserver.dataSetChanged();
115bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
116bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
117bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
118bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    private synchronized void printerRemoved(NsdServiceInfo nsdServiceInfo) {
119bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        boolean wasRemoved = false;
120bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        Set<String> vendors = mVendorHashMap.keySet();
121bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        for(String vendor : vendors) {
122bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            PrinterHashMap map = mVendorHashMap.get(vendor);
123bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
124bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
125bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
126bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        if (wasRemoved) {
127bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            mObserver.dataSetChanged();
128bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
129bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
130bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
131bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public void start() {
132bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        stop();
133bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        for(final String service :mServiceType) {
134bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
135bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                @Override
136bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                public void onStartDiscoveryFailed(String s, int i) {
137bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
138bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
139bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
140bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                @Override
141bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                public void onStopDiscoveryFailed(String s, int i) {
142bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
143bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
144bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
145bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                @Override
146bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                public void onDiscoveryStarted(String s) {
147bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
148bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
149bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
150bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                @Override
151bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                public void onDiscoveryStopped(String s) {
152bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
153bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
154bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
155bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                @Override
156bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
157bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                    mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
158bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
159bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
160bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                @Override
161bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
162bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                    mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
163bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                    printerRemoved(nsdServiceInfo);
164bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann                }
165bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            };
166bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
167bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            mListeners.add(listener);
168bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
169bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
170bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
171bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public void stop() {
172bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        for(NsdManager.DiscoveryListener listener : mListeners) {
173bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
174bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
175bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mVendorHashMap.clear();
176bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        mListeners.clear();
177bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
178bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann
179bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    public Pair<Integer, Integer> getCount() {
180bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        int count = 0;
181bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        for (PrinterHashMap map : mVendorHashMap.values()) {
182bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann            count += map.size();
183bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        }
184bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann        return Pair.create(mVendorHashMap.size(), count);
185bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann    }
186bfaa47233215996b8554a4b7a1a7b36bb3eaf607Philip P. Moltmann}
187