View Javadoc

1   /**
2    *  BlueCove - Java library for Bluetooth
3    *  Copyright (C) 2008 Michael Lifshits
4    *  Copyright (C) 2008 Vlad Skarzhevskyy
5    *
6    *  Licensed to the Apache Software Foundation (ASF) under one
7    *  or more contributor license agreements.  See the NOTICE file
8    *  distributed with this work for additional information
9    *  regarding copyright ownership.  The ASF licenses this file
10   *  to you under the Apache License, Version 2.0 (the
11   *  "License"); you may not use this file except in compliance
12   *  with the License.  You may obtain a copy of the License at
13   *
14   *    http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing,
17   *  software distributed under the License is distributed on an
18   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   *  KIND, either express or implied.  See the License for the
20   *  specific language governing permissions and limitations
21   *  under the License.
22   *
23   *  @author vlads
24   *  @version $Id: EmulatorDeviceInquiry.java 2536 2008-12-09 23:58:58Z skarzhevskyy $
25   */
26  package com.intel.bluetooth;
27  
28  import java.util.Random;
29  import java.util.Vector;
30  
31  import javax.bluetooth.BluetoothStateException;
32  import javax.bluetooth.DeviceClass;
33  import javax.bluetooth.DiscoveryListener;
34  import javax.bluetooth.RemoteDevice;
35  
36  import com.intel.bluetooth.emu.DeviceDescriptor;
37  
38  /**
39   * 
40   */
41  class EmulatorDeviceInquiry implements DeviceInquiryRunnable {
42  
43  	private static final int DISCOVERY_DURATION_ALWAYS = 200;
44  
45  	private static final int DISCOVERY_DURATION_MINIMUM = 500;
46  
47  	private EmulatorLocalDevice localDevice;
48  
49  	private BluetoothStack bluetoothStack;
50  
51  	private DiscoveryListener discoveryListener;
52  
53  	private boolean deviceInquiryCanceled = false;
54  
55  	private Object canceledEvent = new Object();
56  
57  	private static Random rnd;
58  
59  	EmulatorDeviceInquiry(EmulatorLocalDevice localDevice, BluetoothStack bluetoothStack,
60  			DiscoveryListener discoveryListener) {
61  		this.localDevice = localDevice;
62  		this.bluetoothStack = bluetoothStack;
63  		this.discoveryListener = discoveryListener;
64  	}
65  
66  	/*
67  	 * (non-Javadoc)
68  	 * 
69  	 * @see com.intel.bluetooth.DeviceInquiryRunnable#runDeviceInquiry(com.intel.bluetooth.DeviceInquiryThread, int,
70  	 * javax.bluetooth.DiscoveryListener)
71  	 */
72  	public int runDeviceInquiry(DeviceInquiryThread startedNotify, int accessCode, DiscoveryListener listener)
73  			throws BluetoothStateException {
74  		try {
75  			DeviceDescriptor[] devices = localDevice.getDeviceManagerService().getDiscoveredDevices(
76  					localDevice.getAddress());
77  			startedNotify.deviceInquiryStartedCallback();
78  			long start = System.currentTimeMillis();
79  			// Find first device
80  			while (devices.length == 0) {
81  				if (!randomWait(start, -1)) {
82  					break;
83  				}
84  				devices = updateDiscoveredDevices(devices);
85  			}
86  			// Report devices and find a new one
87  			int reportedIndex = 0;
88  			while ((randomWait(start, reportedIndex)) || (reportedIndex < devices.length)) {
89  				if (deviceInquiryCanceled) {
90  					return DiscoveryListener.INQUIRY_TERMINATED;
91  				}
92  				if (reportedIndex < devices.length) {
93  					DeviceDescriptor d = devices[reportedIndex];
94  					// Device may be updated.
95  					d = localDevice.getDeviceManagerService().getDeviceDescriptor(d.getAddress());
96  					reportedIndex++;
97  					RemoteDevice remoteDevice = RemoteDeviceHelper.createRemoteDevice(bluetoothStack, d.getAddress(), d
98  							.getName(), false);
99  					DeviceClass cod = new DeviceClass(d.getDeviceClass());
100 					DebugLog.debug("deviceDiscovered address", remoteDevice.getBluetoothAddress());
101 					DebugLog.debug("deviceDiscovered deviceClass", cod);
102 					listener.deviceDiscovered(remoteDevice, cod);
103 				}
104 				devices = updateDiscoveredDevices(devices);
105 			}
106 
107 			if (deviceInquiryCanceled) {
108 				return DiscoveryListener.INQUIRY_TERMINATED;
109 			}
110 			return DiscoveryListener.INQUIRY_COMPLETED;
111 		} finally {
112 			bluetoothStack.cancelInquiry(discoveryListener);
113 		}
114 	}
115 
116 	private DeviceDescriptor[] updateDiscoveredDevices(DeviceDescriptor[] devices) {
117 		DeviceDescriptor[] newDevices = localDevice.getDeviceManagerService().getDiscoveredDevices(
118 				localDevice.getAddress());
119 		Vector<DeviceDescriptor> discoveredDevice = new Vector<DeviceDescriptor>();
120 		// Old device unchanged
121 		for (int i = 0; i < devices.length; i++) {
122 			discoveredDevice.addElement(devices[i]);
123 		}
124 		// Append new devices if any
125 		newDevicesLoop: for (int i = 0; i < newDevices.length; i++) {
126 			for (int k = 0; k < devices.length; k++) {
127 				if (newDevices[i].getAddress() == devices[k].getAddress()) {
128 					continue newDevicesLoop;
129 				}
130 			}
131 			discoveredDevice.addElement(newDevices[i]);
132 		}
133 		return (DeviceDescriptor[]) discoveredDevice.toArray(new DeviceDescriptor[discoveredDevice.size()]);
134 	}
135 
136 	private boolean randomWait(long start, int device) {
137 		long duration = localDevice.getConfiguration().getDeviceInquiryDuration() * 1000;
138 		if (duration <= 0) {
139 			duration = DISCOVERY_DURATION_MINIMUM;
140 		}
141 		long now = System.currentTimeMillis();
142 		if ((duration == 0) || (now > start + duration)) {
143 			return false;
144 		}
145 		long timeout = duration / 7;
146 		if (localDevice.getConfiguration().isDeviceInquiryRandomDelay()) {
147 			if (rnd == null) {
148 				rnd = new Random();
149 			}
150 			long timeleft = start + duration - now;
151 			if (timeleft > 0) {
152 				timeout = rnd.nextInt((int) timeleft);
153 			}
154 		}
155 		if (device == 0) {
156 			timeout += DISCOVERY_DURATION_ALWAYS;
157 		}
158 
159 		// Limit wait till the end of the duration period
160 		if (now + timeout > start + duration) {
161 			timeout = start + duration - now;
162 		}
163 		if (timeout <= 0) {
164 			return true;
165 		}
166 		synchronized (canceledEvent) {
167 			try {
168 				canceledEvent.wait(timeout);
169 			} catch (InterruptedException e) {
170 				deviceInquiryCanceled = true;
171 			}
172 		}
173 		return true;
174 	}
175 
176 	boolean cancelInquiry(DiscoveryListener listener) {
177 		if (discoveryListener != listener) {
178 			return false;
179 		}
180 		deviceInquiryCanceled = true;
181 		synchronized (canceledEvent) {
182 			canceledEvent.notifyAll();
183 		}
184 		return true;
185 	}
186 
187 	/*
188 	 * (non-Javadoc)
189 	 * 
190 	 * @see com.intel.bluetooth.DeviceInquiryRunnable#deviceDiscoveredCallback(javax.bluetooth.DiscoveryListener, long,
191 	 * int, java.lang.String, boolean)
192 	 */
193 	public void deviceDiscoveredCallback(DiscoveryListener listener, long deviceAddr, int deviceClass,
194 			String deviceName, boolean paired) {
195 	}
196 
197 }