/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2006-2009 Vlad Skarzhevskyy
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @author vlads
* @version $Id$
*/
package net.sf.bluecove.awt;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import javax.bluetooth.BluetoothStateException;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import net.sf.bluecove.Configuration;
import net.sf.bluecove.RemoteDeviceIheritance;
import net.sf.bluecove.TestResponderCommon;
import net.sf.bluecove.util.BluetoothTypesInfo;
import net.sf.bluecove.util.J2MEStringTokenizer;
import net.sf.bluecove.util.Storage;
import org.bluecove.tester.log.Logger;
import org.bluecove.tester.util.RuntimeDetect;
import com.intel.bluetooth.RemoteDeviceHelper;
/**
*
*
*/
public class ClientConnectionDialog extends Dialog {
private static final long serialVersionUID = 1L;
private static final String configConnectionURL = "connectionURL";
private static final String configLastDataSent = "lastDataSent";
Button btnConnect, btnDisconnect, btnCancel, btnSend, btnInterrupt;
TextField tfURL;
Choice choiceAllURLs;
TextField tfData;
Choice choiceDataSendType;
Choice choiceDataReceiveType;
Label status;
Checkbox cbSaveToFile;
Timer monitorTimer;
Object threadLocalBluetoothStack;
String localBluetoothStackAddress = "";
ClientConnectionThread thread;
private Timer sendTimer;
private int connectionWindowID = 0;
private static Vector openConnectionDialogs = new Vector();
private static final String RECENT_RFCOMM_URLS = "recentRFCOMM";
private static Vector recentConnections = new Vector();
private class ConnectionMonitor extends TimerTask {
boolean wasConnected = false;
boolean wasStarted = false;
int connectingCount = 0;
public void run() {
if ((openConnectionDialogs.size() > 1) || (Configuration.hasManyDevices)) {
String title = localBluetoothStackAddress + " Client Connection " + connectionWindowID;
if (thread != null) {
thread.logPrefix = "[" + connectionWindowID + "]";
title += " " + thread.getLocalBluetoothId();
}
ClientConnectionDialog.this.setTitle(title);
}
if (thread == null) {
if (wasConnected || wasStarted) {
status.setText("Idle");
setCursorDefault();
btnDisconnect.setEnabled(false);
btnConnect.setEnabled(true);
btnSend.setEnabled(false);
btnInterrupt.setEnabled(false);
wasConnected = false;
wasStarted = false;
connectingCount = 0;
}
} else if (thread.isRunning) {
if (!wasConnected) {
setCursorDefault();
btnSend.setEnabled(true);
}
wasConnected = true;
if (thread.receivedCount == 0) {
status.setText("Connected");
} else {
status.setText("Received " + thread.receivedCount);
}
} else {
wasStarted = true;
if (thread.isConnecting) {
StringBuffer progress = new StringBuffer("Connecting ");
for (int i = 0; i <= connectingCount; i++) {
progress.append('.');
}
status.setText(progress.toString());
connectingCount++;
} else {
setCursorDefault();
status.setText("Disconnected");
connectingCount = 0;
}
}
}
}
public ClientConnectionDialog(Frame owner) {
super(owner, "Client Connection", false);
TestResponderCommon.initLocalDevice();
Font font = new Font("Monospaced", Font.PLAIN, Configuration.screenSizeSmall ? 9 : 12);
this.setFont(font);
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
Panel panelItems = new BorderPanel(gridbag);
this.add(panelItems, BorderLayout.NORTH);
Label lURL = new Label("URL:");
lURL.setFont(font);
panelItems.add(lURL);
panelItems.add(tfURL = new TextField("", 25));
tfURL.setFont(font);
c.gridwidth = 1;
gridbag.setConstraints(lURL, c);
c.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(tfURL, c);
if (Configuration.storage != null) {
String url = Configuration.storage.retriveData(configConnectionURL);
if (url == null) {
url = Configuration.storage.retriveData(Storage.configLastServiceURL);
}
tfURL.setText(url);
}
Label lDiscovered = new Label("Discovered:");
lDiscovered.setFont(font);
panelItems.add(lDiscovered);
choiceAllURLs = new Choice();
c.gridwidth = 1;
gridbag.setConstraints(lDiscovered, c);
panelItems.add(choiceAllURLs);
c.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(choiceAllURLs, c);
choiceAllURLs.setFont(font);
ServiceRecords.populateChoice(choiceAllURLs, false);
populateRecentConnections(choiceAllURLs);
choiceAllURLs.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
selectURL();
}
});
Label lData = new Label("Data:");
lData.setFont(font);
panelItems.add(lData);
panelItems.add(tfData = new TextField());
tfData.setFont(font);
c.gridwidth = 1;
gridbag.setConstraints(lData, c);
c.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(tfData, c);
if (Configuration.storage != null) {
String d = Configuration.storage.retriveData(configLastDataSent);
if (d != null) {
tfData.setText(d);
}
}
Label l3 = new Label("");
panelItems.add(l3);
c.gridwidth = 1;
gridbag.setConstraints(l3, c);
panelItems.add(btnSend = new Button("Send"));
btnSend.setFont(font);
btnSend.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
send();
}
});
btnSend.setEnabled(false);
c.gridwidth = 1;
gridbag.setConstraints(btnSend, c);
choiceDataSendType = new Choice();
choiceDataSendType.setFont(font);
choiceDataSendType.add("as String.getBytes()+CR");
choiceDataSendType.add("as String.getBytes()");
choiceDataSendType.add("as parseByte(text)");
choiceDataSendType.add("Continuously");
// choiceDataType.add("as byte list");
panelItems.add(choiceDataSendType);
c.gridwidth = 1;
gridbag.setConstraints(choiceDataSendType, c);
Label lReceive = new Label(" Receive:");
lReceive.setFont(font);
panelItems.add(lReceive);
c.gridwidth = 1;
gridbag.setConstraints(lReceive, c);
choiceDataReceiveType = new Choice();
choiceDataReceiveType.setFont(font);
choiceDataReceiveType.add("as char");
choiceDataReceiveType.add("as charArray");
choiceDataReceiveType.add("stats only char");
choiceDataReceiveType.add("stats only charArray");
choiceDataReceiveType.add("do not read");
// choiceDataType.add("as byte list");
// choiceDataReceiveType.add("as Echo");
panelItems.add(choiceDataReceiveType);
c.gridwidth = 1;
gridbag.setConstraints(choiceDataReceiveType, c);
choiceDataReceiveType.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateDataReceiveType();
}
});
Label lRemainder = new Label("");
panelItems.add(lRemainder);
c.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(lRemainder, c);
Label lSaveToFile = new Label("Save to file:");
lSaveToFile.setFont(font);
panelItems.add(lSaveToFile);
panelItems.add(cbSaveToFile = new Checkbox());
c.gridwidth = 1;
gridbag.setConstraints(lSaveToFile, c);
c.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(cbSaveToFile, c);
cbSaveToFile.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateDataReceiveType();
}
});
Label lStatus = new Label("Status:");
lStatus.setFont(font);
panelItems.add(lStatus);
c.gridwidth = 1;
gridbag.setConstraints(lStatus, c);
status = new Label("Idle");
status.setFont(font);
panelItems.add(status);
c.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(status, c);
Panel panelBtns = new Panel();
this.add(panelBtns, BorderLayout.SOUTH);
panelBtns.add(btnConnect = new Button("Connect"));
btnConnect.setFont(font);
btnConnect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
connect();
}
});
panelBtns.add(btnDisconnect = new Button("Disconnect"));
btnDisconnect.setFont(font);
btnDisconnect.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
shutdown();
}
});
btnDisconnect.setEnabled(false);
panelBtns.add(btnInterrupt = new Button("Interrupt"));
btnInterrupt.setFont(font);
btnInterrupt.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
interrupt();
}
});
btnInterrupt.setEnabled(false);
if (RuntimeDetect.isBlueCove) {
Panel panelExtraBtns = panelBtns;
if (Configuration.screenSizeSmall) {
panelExtraBtns = new Panel();
panelItems.add(panelExtraBtns);
c.anchor = GridBagConstraints.EAST;
c.gridwidth = GridBagConstraints.REMAINDER;
;
gridbag.setConstraints(panelExtraBtns, c);
}
Button btnBond = new Button("Bond");
btnBond.setFont(font);
panelExtraBtns.add(btnBond);
btnBond.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onBond();
}
});
Button btnUnBond = new Button("UnBond");
btnUnBond.setFont(font);
panelExtraBtns.add(btnUnBond);
btnUnBond.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onUnBond();
}
});
Button btnInfo = new Button("Info");
btnInfo.setFont(font);
panelExtraBtns.add(btnInfo);
btnInfo.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onInfo();
}
});
}
panelBtns.add(btnCancel = new Button("Cancel"));
btnCancel.setFont(font);
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
onClose();
}
});
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
onClose();
}
});
this.pack();
synchronized (openConnectionDialogs) {
int maxId = 0;
for (Enumeration iter = openConnectionDialogs.elements(); iter.hasMoreElements();) {
ClientConnectionDialog w = (ClientConnectionDialog) iter.nextElement();
if (maxId < w.connectionWindowID) {
maxId = w.connectionWindowID;
}
}
this.connectionWindowID = maxId + 1;
openConnectionDialogs.add(this);
}
OkCancelDialog.centerParent(this);
try {
monitorTimer = new Timer();
monitorTimer.schedule(new ConnectionMonitor(), 1000, 1000);
} catch (Throwable java11) {
}
}
protected void connect() {
if (thread != null) {
thread.shutdown();
thread = null;
}
String url = tfURL.getText();
storeRecentConnection(url);
setCursorWait();
thread = new ClientConnectionThread(url);
thread.setDaemon(true);
if (this.threadLocalBluetoothStack == null) {
this.threadLocalBluetoothStack = Configuration.threadLocalBluetoothStack;
}
thread.threadLocalBluetoothStack = this.threadLocalBluetoothStack;
if (localBluetoothStackAddress.length() == 0) {
try {
LocalDevice localDevice = LocalDevice.getLocalDevice();
String bluetoothAddress = localDevice.getBluetoothAddress();
localBluetoothStackAddress = bluetoothAddress;
String w = TestResponderCommon.getWhiteDeviceName(bluetoothAddress);
if (w != null) {
localBluetoothStackAddress += "[" + w + "]";
}
} catch (BluetoothStateException e) {
Logger.debug("local error", e);
}
}
thread.start();
btnDisconnect.setEnabled(true);
btnInterrupt.setEnabled(true);
btnConnect.setEnabled(false);
updateDataReceiveType();
}
private static void populateRecentConnections(Choice choice) {
loadRecentConnections();
for (Enumeration en = recentConnections.elements(); en.hasMoreElements();) {
choice.add((String) en.nextElement());
}
}
static void loadRecentConnections() {
synchronized (recentConnections) {
if ((recentConnections.size() > 0) || (Configuration.storage == null)) {
return;
}
String urls = Configuration.storage.retriveData(RECENT_RFCOMM_URLS);
if (urls == null) {
return;
}
J2MEStringTokenizer st = new J2MEStringTokenizer(urls, "|");
if (st.hasMoreTokens()) {
while (st.hasMoreTokens()) {
String v = st.nextToken().trim();
if ((v.length() > 0) && (!recentConnections.contains(v))) {
recentConnections.add(v);
}
}
} else {
if (urls.length() > 0) {
recentConnections.add(urls);
}
}
}
}
static void storeRecentConnection(String url) {
if (recentConnections.contains(url)) {
recentConnections.remove(url);
}
recentConnections.add(url);
Configuration.setLastServerURL(url);
if (Configuration.storage == null) {
return;
}
Configuration.storage.storeData(configConnectionURL, url);
StringBuffer h = new StringBuffer();
for (Enumeration iter = recentConnections.elements(); iter.hasMoreElements();) {
h.append((String) iter.nextElement()).append("|");
}
Configuration.storage.storeData(RECENT_RFCOMM_URLS, h.toString());
}
protected void updateDataReceiveType() {
if (thread != null) {
thread.updateDataReceiveType(choiceDataReceiveType.getSelectedIndex(), cbSaveToFile.getState());
}
}
protected void selectURL() {
String url = ServiceRecords.getChoiceURL(choiceAllURLs);
if (url != null) {
tfURL.setText(url);
}
}
protected void send() {
if (thread != null) {
String text = tfData.getText();
if (Configuration.storage != null) {
Configuration.storage.storeData(configLastDataSent, text);
}
int type = choiceDataSendType.getSelectedIndex();
if (type == 3) {
// Continuously
type = 0;
if (sendTimer == null) {
sendTimer = new Timer();
sendTimer.schedule(new TimerTask() {
public void run() {
send();
}
}, 300, 300);
}
} else if (sendTimer != null) {
sendTimer.cancel();
sendTimer = null;
}
byte data[];
switch (type) {
case 0:
data = (text + "\n").getBytes();
break;
case 1:
data = text.getBytes();
break;
case 2:
J2MEStringTokenizer st = new J2MEStringTokenizer(text, ",");
Vector bts = new Vector();
while (st.hasMoreTokens()) {
bts.addElement(st.nextToken().trim());
}
data = new byte[bts.size()];
int j = 0;
for (Enumeration en = bts.elements(); en.hasMoreElements();) {
int i = Integer.parseInt((String) en.nextElement());
data[j] = (byte) (i & 0xFF);
j++;
}
break;
default:
data = new byte[] { 0 };
}
thread.send(data);
} else if (sendTimer != null) {
sendTimer.cancel();
sendTimer = null;
}
}
public void shutdown() {
if (thread != null) {
thread.shutdown();
thread = null;
}
if (sendTimer != null) {
sendTimer.cancel();
sendTimer = null;
}
}
public void interrupt() {
if (thread != null) {
thread.interrupt();
Logger.debug("thread.interrupt() called");
}
}
protected void onClose() {
synchronized (openConnectionDialogs) {
openConnectionDialogs.remove(this);
}
shutdown();
try {
monitorTimer.cancel();
} catch (Throwable java11) {
}
setVisible(false);
}
private void setCursorWait() {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
}
private void setCursorDefault() {
this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
private void onBond() {
boolean test = false;
if (test) {
onNativeFunction();
return;
}
String url = tfURL.getText();
String pinStr = tfData.getText();
if (pinStr.equals("null")) {
pinStr = null;
}
final String pin = pinStr;
final String deviceAddress = BluetoothTypesInfo.extractBluetoothAddress(url);
if (deviceAddress == null) {
Logger.error("invalid url");
return;
}
final RemoteDevice device = new RemoteDeviceIheritance(deviceAddress);
Logger.debug("authenticate:" + deviceAddress + " pin:" + pin);
Thread t = new Thread("Authenticate") {
public void run() {
try {
setCursorWait();
RuntimeDetect.cldcStub.setThreadLocalBluetoothStack(threadLocalBluetoothStack);
boolean rc = RemoteDeviceHelper.authenticate(device, pin);
Logger.info("authenticate returns: " + rc);
} catch (IOException e) {
Logger.error("can't authenticate", e);
} catch (Throwable e) {
Logger.error("authenticate error", e);
} finally {
setCursorDefault();
}
Logger.debug(deviceAddress + " isAuthenticated", device.isAuthenticated());
Logger.debug(deviceAddress + " isTrustedDevice", device.isTrustedDevice());
}
};
t.start();
}
private void onUnBond() {
String url = tfURL.getText();
final String deviceAddress = BluetoothTypesInfo.extractBluetoothAddress(url);
if (deviceAddress == null) {
Logger.error("invalid url");
return;
}
final RemoteDevice device = new RemoteDeviceIheritance(deviceAddress);
Logger.debug("removed authentication:" + deviceAddress);
Thread t = new Thread("UnAuthenticate") {
public void run() {
try {
setCursorWait();
RuntimeDetect.cldcStub.setThreadLocalBluetoothStack(threadLocalBluetoothStack);
RemoteDeviceHelper.removeAuthentication(device);
Logger.info("removed authentication");
} catch (IOException e) {
Logger.error("can't removed authentication", e);
} catch (Throwable e) {
Logger.error("removed authentication error", e);
} finally {
setCursorDefault();
}
Logger.debug(deviceAddress + " isAuthenticated", device.isAuthenticated());
Logger.debug(deviceAddress + " isTrustedDevice", device.isTrustedDevice());
}
};
t.start();
}
private void onNativeFunction() {
String url = tfURL.getText();
try {
String deviceAddress = BluetoothTypesInfo.extractBluetoothAddress(url);
if (deviceAddress == null) {
Logger.error("invalid url");
return;
}
Logger.debug(deviceAddress + " setSniffMode : " + LocalDevice.getProperty("bluecove.nativeFunction:setSniffMode:" + deviceAddress));
// Logger.debug(deviceAddress + " cancelSniffMode : "
// +
// LocalDevice.getProperty("bluecove.nativeFunction:cancelSniffMode:"
// + deviceAddress));
} catch (Throwable e) {
Logger.error("error", e);
}
}
private void onInfo() {
String url = tfURL.getText();
try {
String deviceAddress = BluetoothTypesInfo.extractBluetoothAddress(url);
if (deviceAddress == null) {
Logger.error("invalid url");
return;
}
RemoteDevice device = new RemoteDeviceIheritance(deviceAddress);
Logger.debug(deviceAddress + " isAuthenticated", device.isAuthenticated());
Logger.debug(deviceAddress + " isTrustedDevice", device.isTrustedDevice());
Logger.debug(deviceAddress + " linkMode is:" + LocalDevice.getProperty("bluecove.nativeFunction:getRemoteDeviceLinkMode:" + deviceAddress));
Logger.debug(deviceAddress + " info:" + LocalDevice.getProperty("bluecove.nativeFunction:getRemoteDeviceVersionInfo:" + deviceAddress));
//B4 BlueCove 2.1.1
// Logger.debug(deviceAddress + " RSSI:"
// + LocalDevice.getProperty("bluecove.nativeFunction:getRemoteDeviceRSSI:" + deviceAddress));
try {
Logger.debug(deviceAddress + " RSSI:", RemoteDeviceHelper.readRSSI(device));
} catch (IOException e) {
Logger.debug(deviceAddress + " RSSI:", e.getMessage());
}
} catch (Throwable e) {
Logger.error("error", e);
}
}
}