/* Copyright (C) 2009 Mobile Sorcery AB This program is free software; you can redistribute it and/or modify it under the terms of the Eclipse Public License v1.0. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Eclipse Public License v1.0 for more details. You should have received a copy of the Eclipse Public License v1.0 along with this program. It is also available at http://www.eclipse.org/legal/epl-v10.html */ package com.mobilesorcery.sdk.ui.targetphone.internal.bt; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.MessageFormat; import javax.bluetooth.DeviceClass; import javax.bluetooth.DiscoveryListener; import javax.bluetooth.LocalDevice; import javax.bluetooth.RemoteDevice; import javax.bluetooth.ServiceRecord; import javax.bluetooth.UUID; import javax.microedition.io.Connector; import javax.obex.ClientSession; import javax.obex.HeaderSet; import javax.obex.Operation; import javax.obex.ResponseCodes; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import com.mobilesorcery.sdk.core.Util; /** * * Minimal Services Search example. */ class ServiceSearch { static final UUID OBEX_OBJECT_PUSH = new UUID("1105", true); static int port = -1; public static int search(String address) throws Exception { final Object serviceSearchCompletedEvent = new Object(); DiscoveryListener listener = new DiscoveryListener() { @Override public void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod) { } @Override public void inquiryCompleted(int discType) { } @Override public void servicesDiscovered(int transID, ServiceRecord[] servRecord) { for (int i = 0; i < servRecord.length; i++) { String url = servRecord[i].getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false); if (url == null) { continue; } port = Integer.parseInt(url.substring(22, url.indexOf(';', 22))); System.out.println("port found: " + port); } } @Override public void serviceSearchCompleted(int transID, int respCode) { System.out.println("service search completed."); synchronized (serviceSearchCompletedEvent) { serviceSearchCompletedEvent.notifyAll(); } } }; UUID[] searchUuidSet = new UUID[] { OBEX_OBJECT_PUSH }; // int[] attrIDs = new int[] {}; class MyRemoteDevice extends RemoteDevice { public MyRemoteDevice(String address) { super(address); } } ; RemoteDevice btDevice = new MyRemoteDevice(address); synchronized (serviceSearchCompletedEvent) { System.out.println("search services on " + btDevice.getBluetoothAddress() + " " + btDevice.getFriendlyName(false)); LocalDevice.getLocalDevice().getDiscoveryAgent().searchServices(null, searchUuidSet, btDevice, listener); serviceSearchCompletedEvent.wait(); if (port == -1) throw new IOException("No service port found"); return port; } } } public class Bcobex { /** * This specifies the size of the chunks in which a file * sent to a device. */ private static final int TRANSPORT_CHUNK_SIZE = 65536; static { /* OS X is slow when sending packages to a device, the below * line increases the MTU (Maximum Transferable Unit), so * that transfers is a bit faster (about 2 times compared to * the default value). */ if( System.getProperty("os.name").toLowerCase().contains("mac") ) { System.setProperty("bluecove.obex.mtu", "4096"); } }; public static void main(String[] args) throws Exception { if (args == null || args.length != 2) { System.out.println("Usage: bcobex <address> <file>\n" + "\n" + "Sends file to bluetooth address.\n" + "Address format: %012x\n" + "\n" + "Example: bcobex 012345689ABC someApp.jar\n" + "\n"); return; } String address = args[0]; String filename = args[1]; int port = ServiceSearch.search(address); sendObexFile(address, port, filename); } public static void sendObexFile(String address, int port, String filename) throws IOException { sendObexFile(address, port, new File(filename), new NullProgressMonitor()); } public static void sendObexFile(String address, int port, File file, IProgressMonitor monitor) throws IOException { // MB: Added eclipse-specific code 080815. String url = "btgoep://" + address + ":" + port; if (!file.exists()) { throw new IOException("Could not find file"); } if (file.isDirectory()) { throw new IOException("File is a directory"); } OutputStream os = null; InputStream fileInput = null; Operation putOperation = null; ClientSession clientSession = null; try { long length = file.length(); monitor.beginTask("Sending file", (int) file.length()); fileInput = new FileInputStream(file); monitor.setTaskName(MessageFormat.format("Connecting to {0}", url)); clientSession = (ClientSession) Connector.open(url); HeaderSet hsConnectReply = clientSession.connect(null); if (hsConnectReply.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) { throw new IOException("OBEX failed to connect"); } monitor.setTaskName("Connected."); HeaderSet head = clientSession.createHeaderSet(); head.setHeader(HeaderSet.NAME, file.getName()); head.setHeader(HeaderSet.LENGTH, length); // Create PUT Operation putOperation = clientSession.put(head); // Send data to server os = putOperation.openOutputStream(); byte[] buffer = new byte[TRANSPORT_CHUNK_SIZE]; // Just an unusual number... int totalRead = 0; boolean firstChunk = true; for (int read = fileInput.read(buffer); !monitor.isCanceled() && read != -1; read = fileInput.read(buffer)) { totalRead += read; os.write(buffer, 0, read); if (firstChunk) { monitor.setTaskName("Transfer in progress... (you may need to accept this transfer on the device)"); firstChunk = false; } else { monitor.setTaskName(MessageFormat.format("Sent {0} of {1}", Util.dataSize(totalRead), Util.dataSize(length))); } monitor.worked(read); } } finally { if (os != null) { os.close(); } if (fileInput != null) { fileInput.close(); } if (putOperation != null) { putOperation.close(); } if (clientSession != null) { clientSession.disconnect(null); clientSession.close(); } } monitor.setTaskName("Sent file to device"); monitor.done(); } public static void sendObexFile(BTTargetPhone phone, File file, IProgressMonitor monitor) throws IOException { sendObexFile(phone.getAddress(), phone.getPort(), file, monitor); } }