ContextMap.java revision 337ee9418b0122e6a89ff38cd49f031ba80aa24c
103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta/*
203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Copyright (C) 2013 The Android Open Source Project
303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *
403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Licensed under the Apache License, Version 2.0 (the "License");
503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * you may not use this file except in compliance with the License.
603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * You may obtain a copy of the License at
703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *
803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *      http://www.apache.org/licenses/LICENSE-2.0
903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *
1003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Unless required by applicable law or agreed to in writing, software
1103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * distributed under the License is distributed on an "AS IS" BASIS,
1203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * See the License for the specific language governing permissions and
1403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * limitations under the License.
1503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta */
166af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachpackage com.android.bluetooth.gatt;
1703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
18f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panickerimport android.bluetooth.le.ScanSettings;
198a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panickerimport android.content.Context;
208a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panickerimport android.os.Binder;
216af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.IBinder;
226af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.IBinder.DeathRecipient;
236af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.IInterface;
246af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.RemoteException;
2503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport android.util.Log;
265c07523b0b5d32176d7ff3ab28555123123261ddAjay Panickerimport java.text.DateFormat;
275c07523b0b5d32176d7ff3ab28555123123261ddAjay Panickerimport java.text.SimpleDateFormat;
2803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.ArrayList;
295c07523b0b5d32176d7ff3ab28555123123261ddAjay Panickerimport java.util.Date;
306af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport java.util.HashSet;
3103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.Iterator;
328a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panickerimport java.util.LinkedList;
3303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.List;
346af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport java.util.NoSuchElementException;
3503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.Set;
3603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.UUID;
37f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Aroraimport java.util.HashMap;
38f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Aroraimport java.util.Map;
3903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
403122e5171ef26ff487f10826786606df848ca25eAjay Panickerimport com.android.bluetooth.btservice.BluetoothProto;
413122e5171ef26ff487f10826786606df848ca25eAjay Panicker
4203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta/**
4303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Helper class that keeps track of registered GATT applications.
4403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * This class manages application callbacks and keeps track of GATT connections.
4503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * @hide
4603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta */
4703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta/*package*/ class ContextMap<T> {
4803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap";
4903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
505c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker    static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
513122e5171ef26ff487f10826786606df848ca25eAjay Panicker    static final int NUM_SCAN_EVENTS_KEPT = 20;
523122e5171ef26ff487f10826786606df848ca25eAjay Panicker    ArrayList<BluetoothProto.ScanEvent> mScanEvents =
533122e5171ef26ff487f10826786606df848ca25eAjay Panicker      new ArrayList<BluetoothProto.ScanEvent>(NUM_SCAN_EVENTS_KEPT);
543122e5171ef26ff487f10826786606df848ca25eAjay Panicker
5503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
568a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     * ScanStats class helps keep track of information about scans
578a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     * on a per application basis.
588a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     */
598a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    class ScanStats {
60337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
61337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker        class LastScan {
62337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            long durration;
63337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            long timestamp;
64337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            boolean opportunistic;
65337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            boolean background;
66337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
67337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            public LastScan(long timestamp, long durration,
68337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                            boolean opportunistic, boolean background) {
69337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                this.durration = durration;
70337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                this.timestamp = timestamp;
71337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                this.opportunistic = opportunistic;
72337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                this.background = background;
73337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            }
74337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker        }
75337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
768a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        static final int NUM_SCAN_DURATIONS_KEPT = 5;
778a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
783122e5171ef26ff487f10826786606df848ca25eAjay Panicker        String appName;
798a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        int scansStarted = 0;
808a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        int scansStopped = 0;
818a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        boolean isScanning = false;
828a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        boolean isRegistered = false;
83f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panicker        boolean isOpportunisticScan = false;
84f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panicker        boolean isBackgroundScan = false;
858a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        long minScanTime = Long.MAX_VALUE;
868a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        long maxScanTime = 0;
878a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        long totalScanTime = 0;
88337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker        List<LastScan> lastScans = new ArrayList<LastScan>(NUM_SCAN_DURATIONS_KEPT + 1);
898a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        long startTime = 0;
908a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        long stopTime = 0;
918a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
923122e5171ef26ff487f10826786606df848ca25eAjay Panicker        public ScanStats(String name) {
933122e5171ef26ff487f10826786606df848ca25eAjay Panicker            appName = name;
943122e5171ef26ff487f10826786606df848ca25eAjay Panicker        }
953122e5171ef26ff487f10826786606df848ca25eAjay Panicker
96a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker        synchronized void recordScanStart(ScanSettings settings) {
97ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker            if (isScanning)
98ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker                return;
99ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker
1008a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            this.scansStarted++;
1018a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            isScanning = true;
1028a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            startTime = System.currentTimeMillis();
103ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker
104f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panicker            if (settings != null) {
105f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panicker                isOpportunisticScan = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC;
106f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panicker                isBackgroundScan = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0;
107f0202e094a55e51d1e1399f18ad255fb636dd381Ajay Panicker            }
1083122e5171ef26ff487f10826786606df848ca25eAjay Panicker
1093122e5171ef26ff487f10826786606df848ca25eAjay Panicker            BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent();
1103122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_START);
1113122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE);
1123122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setInitiator(appName);
1133122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setEventTimeMillis(System.currentTimeMillis());
1145c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker
115337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            lastScans.add(new LastScan(startTime, 0, false, false));
116337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
117337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            if (settings != null) {
118337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker              isOpportunisticScan = settings.getScanMode() == ScanSettings.SCAN_MODE_OPPORTUNISTIC;
119337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker              isBackgroundScan = (settings.getCallbackType() & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0;
1205c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker            }
1215c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker
1223122e5171ef26ff487f10826786606df848ca25eAjay Panicker            synchronized(mScanEvents) {
1233122e5171ef26ff487f10826786606df848ca25eAjay Panicker                if(mScanEvents.size() == NUM_SCAN_EVENTS_KEPT)
1243122e5171ef26ff487f10826786606df848ca25eAjay Panicker                    mScanEvents.remove(0);
1253122e5171ef26ff487f10826786606df848ca25eAjay Panicker                mScanEvents.add(scanEvent);
1263122e5171ef26ff487f10826786606df848ca25eAjay Panicker            }
1278a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
1288a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
129a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker        synchronized void recordScanStop() {
130ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker            if (!isScanning)
131ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker              return;
132ef437b17ba8b192488cb77ffd39daa3e83ba4aeaAjay Panicker
1338a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            this.scansStopped++;
1348a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            isScanning = false;
1358a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            stopTime = System.currentTimeMillis();
1368a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            long currTime = stopTime - startTime;
1378a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
1388a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            minScanTime = Math.min(currTime, minScanTime);
1398a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            maxScanTime = Math.max(currTime, maxScanTime);
1408a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            totalScanTime += currTime;
141337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
142337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            LastScan curr = lastScans.get(lastScans.size() - 1);
143337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            curr.durration = currTime;
144337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            curr.opportunistic = isOpportunisticScan;
145337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            curr.background = isBackgroundScan;
146337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
147337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            isOpportunisticScan = false;
148337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            isBackgroundScan = false;
149337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
1508a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            if (lastScans.size() > NUM_SCAN_DURATIONS_KEPT) {
1518a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker                lastScans.remove(0);
1528a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            }
1533122e5171ef26ff487f10826786606df848ca25eAjay Panicker
1543122e5171ef26ff487f10826786606df848ca25eAjay Panicker            BluetoothProto.ScanEvent scanEvent = new BluetoothProto.ScanEvent();
1553122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setScanEventType(BluetoothProto.ScanEvent.SCAN_EVENT_STOP);
1563122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setScanTechnologyType(BluetoothProto.ScanEvent.SCAN_TECH_TYPE_LE);
1573122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setInitiator(appName);
1583122e5171ef26ff487f10826786606df848ca25eAjay Panicker            scanEvent.setEventTimeMillis(System.currentTimeMillis());
1593122e5171ef26ff487f10826786606df848ca25eAjay Panicker            synchronized(mScanEvents) {
1603122e5171ef26ff487f10826786606df848ca25eAjay Panicker                if (mScanEvents.size() == NUM_SCAN_EVENTS_KEPT)
1613122e5171ef26ff487f10826786606df848ca25eAjay Panicker                    mScanEvents.remove(0);
1623122e5171ef26ff487f10826786606df848ca25eAjay Panicker                mScanEvents.add(scanEvent);
1633122e5171ef26ff487f10826786606df848ca25eAjay Panicker            }
1648a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
165a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
166a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker        synchronized void dumpToString(StringBuilder sb) {
167a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            long currTime = System.currentTimeMillis();
168a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            long maxScan = maxScanTime;
169a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            long minScan = minScanTime;
170a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            long currScan = 0;
171a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
172a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (isScanning) {
173a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                currScan = currTime - startTime;
174a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                minScan = Math.min(currScan, minScan);
175a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                maxScan = Math.max(currScan, maxScan);
176a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            }
177a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
178a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (minScan == Long.MAX_VALUE) {
179a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                minScan = 0;
180a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            }
181a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
182a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            long lastScan = 0;
183a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (stopTime != 0) {
184a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                lastScan = currTime - stopTime;
185a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            }
186a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
187a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            long avgScan = 0;
188a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (scansStarted > 0) {
189a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                avgScan = (totalScanTime + currScan) / scansStarted;
190a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            }
191a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
192a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            sb.append("  " + appName);
193a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (isRegistered) sb.append(" (Registered)");
194a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (isOpportunisticScan) sb.append(" (Opportunistic)");
195a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (isBackgroundScan) sb.append(" (Background)");
196a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            sb.append("\n");
197a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
198337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            sb.append("  LE scans (started/stopped)         : " +
199a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                      scansStarted + " / " +
200a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                      scansStopped + "\n");
201337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            sb.append("  Scan time in ms (min/max/avg/total): " +
202a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                      minScan + " / " +
203a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                      maxScan + " / " +
204337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                      avgScan + " / " +
205337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                      totalScanTime + "\n");
206a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
207a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (lastScans.size() != 0) {
208337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                int lastScansSize = scansStopped < NUM_SCAN_DURATIONS_KEPT ?
209337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                                    scansStopped : NUM_SCAN_DURATIONS_KEPT;
210337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                sb.append("  Last " + lastScansSize +
211337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                          " scans                       :\n");
212337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker
213337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                for (int i = 0; i < lastScansSize; i++) {
214337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    LastScan scan = lastScans.get(i);
215337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    Date timestamp = new Date(scan.timestamp);
216a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                    sb.append("    " + dateFormat.format(timestamp) + " - ");
217337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    sb.append(scan.durration + "ms ");
218337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    if (scan.opportunistic) sb.append("Opp ");
219337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    if (scan.background) sb.append("Back");
220337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    sb.append("\n");
221a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                }
222a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            }
223a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
224a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            if (isRegistered) {
225a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                App appEntry = getByName(appName);
226337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                sb.append("  Application ID                     : " +
227a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                          appEntry.id + "\n");
228337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                sb.append("  UUID                               : " +
229a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                          appEntry.uuid + "\n");
230a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
231a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                if (isScanning) {
232337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    sb.append("  Current scan duration in ms        : " +
233a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                              currScan + "\n");
234a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                }
235a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
236a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                List<Connection> connections = getConnectionByApp(appEntry.id);
237a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                sb.append("  Connections: " + connections.size() + "\n");
238a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker
239a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                Iterator<Connection> ii = connections.iterator();
240a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                while(ii.hasNext()) {
241a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                    Connection connection = ii.next();
242337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                    long connectionTime = System.currentTimeMillis() - connection.startTime;
243a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                    sb.append("    " + connection.connId + ": " +
244337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker                              connection.address + " " + connectionTime + "ms\n");
245a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker                }
246a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            }
247a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            sb.append("\n");
248a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker        }
2498a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    }
2508a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
2518a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /**
25203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Connection class helps map connection IDs to device addresses.
25303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
25403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    class Connection {
25503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        int connId;
25603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        String address;
25703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        int appId;
258337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker        long startTime;
25903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
26003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Connection(int connId, String address,int appId) {
26103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.connId = connId;
26203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.address = address;
26303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.appId = appId;
264337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            this.startTime = System.currentTimeMillis();
26503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
26603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
26703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
26803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
26903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Application entry mapping UUIDs to appIDs and callbacks.
27003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
27103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    class App {
27203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /** The UUID of the application */
27303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        UUID uuid;
27403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
27503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /** The id of the application */
27603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        int id;
27703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
2788a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        /** The package name of the application */
2798a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        String name;
2808a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
28103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /** Application callbacks */
28203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        T callback;
28303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
2846af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        /** Death receipient */
2856af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        private IBinder.DeathRecipient mDeathRecipient;
2866af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
287934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        /** Flag to signal that transport is congested */
288934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        Boolean isCongested = false;
289934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
290934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        /** Internal callback info queue, waiting to be send on congestion clear */
291934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        private List<CallbackInfo> congestionQueue = new ArrayList<CallbackInfo>();
292934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
29303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /**
29403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta         * Creates a new app context.
29503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta         */
2968a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        App(UUID uuid, T callback, String name) {
29703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.uuid = uuid;
29803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.callback = callback;
2998a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            this.name = name;
30003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
3016af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
3026af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        /**
3036af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         * Link death recipient
3046af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         */
3056af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        void linkToDeath(IBinder.DeathRecipient deathRecipient) {
3066af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            try {
3076af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                IBinder binder = ((IInterface)callback).asBinder();
3086af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                binder.linkToDeath(deathRecipient, 0);
3096af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                mDeathRecipient = deathRecipient;
3106af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            } catch (RemoteException e) {
3116af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                Log.e(TAG, "Unable to link deathRecipient for app id " + id);
3126af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
3136af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
3146af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
3156af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        /**
3166af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         * Unlink death recipient
3176af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         */
3186af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        void unlinkToDeath() {
3196af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            if (mDeathRecipient != null) {
3206af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                try {
3216af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    IBinder binder = ((IInterface)callback).asBinder();
3226af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    binder.unlinkToDeath(mDeathRecipient,0);
3236af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                } catch (NoSuchElementException e) {
3246af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    Log.e(TAG, "Unable to unlink deathRecipient for app id " + id);
3256af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                }
3266af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
3276af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
328934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
329934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        void queueCallback(CallbackInfo callbackInfo) {
330934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham            congestionQueue.add(callbackInfo);
331934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        }
332934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
333934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        CallbackInfo popQueuedCallback() {
334934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham            if (congestionQueue.size() == 0) return null;
335934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham            return congestionQueue.remove(0);
336934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        }
33703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
33803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
33903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /** Our internal application list */
34003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    List<App> mApps = new ArrayList<App>();
34103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
3428a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /** Internal map to keep track of logging information by app name */
3438a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    HashMap<String, ScanStats> mScanStats = new HashMap<String, ScanStats>();
3448a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
34503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /** Internal list of connected devices **/
34603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    Set<Connection> mConnections = new HashSet<Connection>();
34703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
34803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
34903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Add an entry to the application context list.
35003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
3518a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    void add(UUID uuid, T callback, Context context) {
3528a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        String appName = context.getPackageManager().getNameForUid(
3538a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker                             Binder.getCallingUid());
3548a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        if (appName == null) {
3558a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            // Assign an app name if one isn't found
3568a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            appName = "Unknown App (UID: " + Binder.getCallingUid() + ")";
3578a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
3586af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mApps) {
3598a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            mApps.add(new App(uuid, callback, appName));
3608a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            ScanStats scanStats = mScanStats.get(appName);
3618a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            if (scanStats == null) {
3623122e5171ef26ff487f10826786606df848ca25eAjay Panicker                scanStats = new ScanStats(appName);
3638a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker                mScanStats.put(appName, scanStats);
3648a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            }
3658a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            scanStats.isRegistered = true;
3666af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
36703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
36803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
36903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
3703f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach     * Remove the context for a given UUID
3713f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach     */
3723f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach    void remove(UUID uuid) {
3733f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach        synchronized (mApps) {
3743f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach            Iterator<App> i = mApps.iterator();
3758a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
3763f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                App entry = i.next();
3773f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                if (entry.uuid.equals(uuid)) {
3783f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                    entry.unlinkToDeath();
3798a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker                    mScanStats.get(entry.name).isRegistered = false;
3803f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                    i.remove();
3813f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                    break;
3823f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                }
3833f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach            }
3843f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach        }
3853f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach    }
3863f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach
3873f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach    /**
38803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Remove the context for a given application ID.
38903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
39003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void remove(int id) {
3916af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mApps) {
3926af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            Iterator<App> i = mApps.iterator();
3938a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
3946af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                App entry = i.next();
3956af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                if (entry.id == id) {
3966af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    entry.unlinkToDeath();
3978a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker                    mScanStats.get(entry.name).isRegistered = false;
3986af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    i.remove();
3996af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    break;
4006af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                }
40103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            }
40203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
40303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
40403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
40503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
40603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Add a new connection for a given application ID.
40703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
40803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void addConnection(int id, int connId, String address) {
4096af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mConnections) {
4106af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            App entry = getById(id);
4116af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            if (entry != null){
4126af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                mConnections.add(new Connection(connId, address, id));
4136af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
41403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
41503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
41603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
41703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
41803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Remove a connection with the given ID.
41903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
42003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void removeConnection(int id, int connId) {
4216af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mConnections) {
4226af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            Iterator<Connection> i = mConnections.iterator();
4238a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
4246af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                Connection connection = i.next();
4256af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                if (connection.connId == connId) {
4266af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    i.remove();
4276af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    break;
4286af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                }
42903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            }
43003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
43103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
43203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
43303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
43403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get an application context by ID.
43503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
43603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    App getById(int id) {
43703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<App> i = mApps.iterator();
4388a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
43903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            App entry = i.next();
44003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (entry.id == id) return entry;
44103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
44203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Log.e(TAG, "Context not found for ID " + id);
44303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
44403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
44503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
44603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
44703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get an application context by UUID.
44803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
44903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    App getByUuid(UUID uuid) {
45003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<App> i = mApps.iterator();
4518a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
45203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            App entry = i.next();
45303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (entry.uuid.equals(uuid)) return entry;
45403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
45503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Log.e(TAG, "Context not found for UUID " + uuid);
45603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
45703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
45803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
45903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
4608a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     * Get an application context by the calling Apps name.
4618a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     */
4628a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    App getByName(String name) {
4638a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        Iterator<App> i = mApps.iterator();
4648a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
4658a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            App entry = i.next();
4668a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            if (entry.name.equals(name)) return entry;
4678a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
4688a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        Log.e(TAG, "Context not found for name " + name);
4698a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        return null;
4708a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    }
4718a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
4728a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /**
4738a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     * Get Logging info by ID
4748a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     */
4758a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    ScanStats getScanStatsById(int id) {
4768a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        App temp = getById(id);
4778a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        if (temp != null) {
4788a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            return mScanStats.get(temp.name);
4798a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
4808a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        return null;
4818a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    }
4828a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
4838a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /**
4843122e5171ef26ff487f10826786606df848ca25eAjay Panicker     * Get Logging info by application name
4853122e5171ef26ff487f10826786606df848ca25eAjay Panicker     */
4863122e5171ef26ff487f10826786606df848ca25eAjay Panicker    ScanStats getScanStatsByName(String name) {
4873122e5171ef26ff487f10826786606df848ca25eAjay Panicker        return mScanStats.get(name);
4883122e5171ef26ff487f10826786606df848ca25eAjay Panicker    }
4893122e5171ef26ff487f10826786606df848ca25eAjay Panicker
4903122e5171ef26ff487f10826786606df848ca25eAjay Panicker    /**
49103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get the device addresses for all connected devices
49203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
49303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    Set<String> getConnectedDevices() {
49403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Set<String> addresses = new HashSet<String>();
49503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
4968a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
49703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
49803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            addresses.add(connection.address);
49903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
50003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return addresses;
50103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
50203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
50303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
50403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get an application context by a connection ID.
50503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
50603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    App getByConnId(int connId) {
50703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> ii = mConnections.iterator();
5088a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (ii.hasNext()) {
50903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = ii.next();
51003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.connId == connId){
51103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta                return getById(connection.appId);
51203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            }
51303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
51403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
51503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
51603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
51703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
51803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Returns a connection ID for a given device address.
51903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
52003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    Integer connIdByAddress(int id, String address) {
52103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        App entry = getById(id);
52203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        if (entry == null) return null;
52303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
52403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
5258a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
52603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
52703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.address.equals(address) && connection.appId == id)
52803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta                return connection.connId;
52903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
53003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
53103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
53203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
53303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
53403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Returns the device address for a given connection ID.
53503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
53603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    String addressByConnId(int connId) {
53703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
5388a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
53903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
54003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.connId == connId) return connection.address;
54103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
54203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
54303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
54403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
54503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    List<Connection> getConnectionByApp(int appId) {
54603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        List<Connection> currentConnections = new ArrayList<Connection>();
54703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
5488a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
54903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
55003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.appId == appId)
55103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta                currentConnections.add(connection);
55203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
55303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return currentConnections;
55403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
55503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
55603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
55703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Erases all application context entries.
55803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
55903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void clear() {
5606af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mApps) {
5616af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            Iterator<App> i = mApps.iterator();
5628a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
5636af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                App entry = i.next();
5646af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                entry.unlinkToDeath();
5656af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                i.remove();
5666af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
5676af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
5686af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
5696af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mConnections) {
5706af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            mConnections.clear();
5716af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
57203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
57303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
57403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
575f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora     * Returns connect device map with addr and appid
576f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora     */
577f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora    Map<Integer, String> getConnectedMap(){
578f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        Map<Integer, String> connectedmap = new HashMap<Integer, String>();
579f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        for(Connection conn: mConnections){
580f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora            connectedmap.put(conn.appId, conn.address);
581f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        }
582f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        return connectedmap;
583f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora    }
584f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora
585f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora    /**
58603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Logs debug information.
58703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
588a02de6484f9b6cac6b8c811edae11be55746b555Andre Eisenbach    void dump(StringBuilder sb) {
5898a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        sb.append("  Entries: " + mScanStats.size() + "\n\n");
5908a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
5915c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker        Iterator<Map.Entry<String,ScanStats>> it = mScanStats.entrySet().iterator();
5925c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker        while (it.hasNext()) {
5935c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker            Map.Entry<String, ScanStats> entry = it.next();
59403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
5958a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            String name = entry.getKey();
5968a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            ScanStats scanStats = entry.getValue();
597a0ff3af53c2299fc20d4c1cc2bcced4a0d2ff5c9Ajay Panicker            scanStats.dumpToString(sb);
59803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
59903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
6003122e5171ef26ff487f10826786606df848ca25eAjay Panicker
6013122e5171ef26ff487f10826786606df848ca25eAjay Panicker    void dumpProto(BluetoothProto.BluetoothLog proto) {
6023122e5171ef26ff487f10826786606df848ca25eAjay Panicker        synchronized(mScanEvents) {
6033122e5171ef26ff487f10826786606df848ca25eAjay Panicker            for (BluetoothProto.ScanEvent event : mScanEvents) {
6043122e5171ef26ff487f10826786606df848ca25eAjay Panicker                proto.addScanEvent(event);
6053122e5171ef26ff487f10826786606df848ca25eAjay Panicker            }
6063122e5171ef26ff487f10826786606df848ca25eAjay Panicker        }
6073122e5171ef26ff487f10826786606df848ca25eAjay Panicker    }
60803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta}
609