109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/* 209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc. 309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * 409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * All rights reserved. 509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * 609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Redistribution and use in source and binary forms, with or without 709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * modification, are permitted provided that the following conditions are met: 809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * 909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Redistributions of source code must retain the above copyright notice, 1009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * this list of conditions and the following disclaimer. 1109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * 1209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice, 1309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * this list of conditions and the following disclaimer in the documentation 1409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * and/or other materials provided with the distribution. 1509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * 1609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors 1709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * may be used to endorse or promote products derived from this software 1809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * without specific prior written permission. 1909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * 2009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * POSSIBILITY OF SUCH DAMAGE. 3109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */ 3209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 3309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypackage com.android.bluetooth.opp; 3409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 3509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ClientOperation; 3609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ClientSession; 3709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.HeaderSet; 3809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ObexTransport; 3909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ResponseCodes; 4009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.ContentValues; 4209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Context; 4309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.net.Uri; 4409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Handler; 4509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Message; 4609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.PowerManager; 4752236de777c23788df8147de15912a57e8bc36ddTao Liejunimport android.os.PowerManager.WakeLock; 4809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Process; 4909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.util.Log; 5009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 5109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.BufferedInputStream; 5209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.IOException; 5309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.InputStream; 5409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.OutputStream; 5509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.lang.Thread; 5609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 5709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/** 5809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * This class runs as an OBEX client 5909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */ 6009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypublic class BluetoothOppObexClientSession implements BluetoothOppObexSession { 6109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 6274ae04c73312403e89db0f8e9bd9601d403b4783fredc private static final String TAG = "BtOppObexClient"; 63ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly private static final boolean D = Constants.DEBUG; 64ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly private static final boolean V = Constants.VERBOSE; 6509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 6609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private ClientThread mThread; 6709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 6809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private ObexTransport mTransport; 6909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 7009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private Context mContext; 7109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 7209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private volatile boolean mInterrupted; 7309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 7409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private volatile boolean mWaitingForRemote; 7509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 7609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private Handler mCallback; 7709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 7809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public BluetoothOppObexClientSession(Context context, ObexTransport transport) { 7909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (transport == null) { 8009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly throw new NullPointerException("transport is null"); 8109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 8209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mContext = context; 8309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mTransport = transport; 8409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 8509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 868eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen public void start(Handler handler, int numShares) { 87ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Start!"); 8809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCallback = handler; 898eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen mThread = new ClientThread(mContext, mTransport, numShares); 9009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mThread.start(); 9109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 9209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 9309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void stop() { 94ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Stop!"); 9509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mThread != null) { 9609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mInterrupted = true; 9709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 9809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mThread.interrupt(); 99ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "waiting for thread to terminate"); 10009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mThread.join(); 10109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mThread = null; 10209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e) { 103ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Interrupted waiting for thread to join"); 10409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 10509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 10609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCallback = null; 10709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 10809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 10909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void addShare(BluetoothOppShareInfo share) { 11009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mThread.addShare(share); 11109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 11209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 1130ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang private static int readFully(InputStream is, byte[] buffer, int size) throws IOException { 1140ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang int done = 0; 1150ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang while (done < size) { 1160ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang int got = is.read(buffer, done, size - done); 1170ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang if (got <= 0) break; 1180ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang done += got; 1190ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang } 1200ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang return done; 1210ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang } 1220ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang 12309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private class ClientThread extends Thread { 12452236de777c23788df8147de15912a57e8bc36ddTao Liejun 1251ac5507790a87810061a19dadec36eb328a222eaTao Liejun private static final int sSleepTime = 500; 12609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 1276769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun private Context mContext1; 12809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 12909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private BluetoothOppShareInfo mInfo; 13009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 13109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private volatile boolean waitingForShare; 13209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 1336769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun private ObexTransport mTransport1; 13409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 13509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private ClientSession mCs; 13609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 13752236de777c23788df8147de15912a57e8bc36ddTao Liejun private WakeLock wakeLock; 13809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 1396769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun private BluetoothOppSendFileInfo mFileInfo = null; 14009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 1411ac5507790a87810061a19dadec36eb328a222eaTao Liejun private boolean mConnected = false; 1421ac5507790a87810061a19dadec36eb328a222eaTao Liejun 1438eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen private int mNumShares; 1448eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen 1458eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen public ClientThread(Context context, ObexTransport transport, int initialNumShares) { 1461ac5507790a87810061a19dadec36eb328a222eaTao Liejun super("BtOpp ClientThread"); 1471ac5507790a87810061a19dadec36eb328a222eaTao Liejun mContext1 = context; 1481ac5507790a87810061a19dadec36eb328a222eaTao Liejun mTransport1 = transport; 1491ac5507790a87810061a19dadec36eb328a222eaTao Liejun waitingForShare = true; 1501ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = false; 1518eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen mNumShares = initialNumShares; 1521ac5507790a87810061a19dadec36eb328a222eaTao Liejun PowerManager pm = (PowerManager)mContext1.getSystemService(Context.POWER_SERVICE); 1531ac5507790a87810061a19dadec36eb328a222eaTao Liejun wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 1541ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 1551ac5507790a87810061a19dadec36eb328a222eaTao Liejun 15609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void addShare(BluetoothOppShareInfo info) { 15709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mInfo = info; 15809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mFileInfo = processShareInfo(); 15909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly waitingForShare = false; 16009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 16109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 16209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly @Override 16309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void run() { 16409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 16509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 166ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "acquire partial WakeLock"); 16709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly wakeLock.acquire(); 16852236de777c23788df8147de15912a57e8bc36ddTao Liejun 16909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 17009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Thread.sleep(100); 17109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e1) { 172ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Client thread was interrupted (1), exiting"); 17309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mInterrupted = true; 17409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 17509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!mInterrupted) { 1768eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen connect(mNumShares); 17709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 1781ac5507790a87810061a19dadec36eb328a222eaTao Liejun 17909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly while (!mInterrupted) { 18009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!waitingForShare) { 18109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly doSend(); 18209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 18309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 184ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Client thread waiting for next share, sleep for " 1851ac5507790a87810061a19dadec36eb328a222eaTao Liejun + sSleepTime); 1861ac5507790a87810061a19dadec36eb328a222eaTao Liejun Thread.sleep(sSleepTime); 18709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e) { 18809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 18909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 19009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 19109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 19209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly disconnect(); 1936769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun 1941ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (wakeLock.isHeld()) { 195ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "release partial WakeLock"); 1961ac5507790a87810061a19dadec36eb328a222eaTao Liejun wakeLock.release(); 19709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 19809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 19909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SESSION_COMPLETE; 20009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.obj = mInfo; 20109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 2021ac5507790a87810061a19dadec36eb328a222eaTao Liejun 20309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 20409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 20509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private void disconnect() { 20609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 20709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mCs != null) { 20809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCs.disconnect(null); 20909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 21009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCs = null; 211ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session disconnected"); 21209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 2131ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.w(TAG, "OBEX session disconnect error" + e); 21409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 21509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 21609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mCs != null) { 217ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session close mCs"); 21809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCs.close(); 219ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session closed"); 22009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 22109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 2221ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.w(TAG, "OBEX session close error" + e); 22309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2246769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun if (mTransport1 != null) { 22509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 2266769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mTransport1.close(); 22709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 22809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "mTransport.close error"); 22909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 23009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 23109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 23209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 23309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 2348eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen private void connect(int numShares) { 235ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Create ClientSession with transport " + mTransport1.toString()); 2366769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun try { 2376769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mCs = new ClientSession(mTransport1); 2381ac5507790a87810061a19dadec36eb328a222eaTao Liejun mConnected = true; 2396769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun } catch (IOException e1) { 2406769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Log.e(TAG, "OBEX session create error"); 24109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2421ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (mConnected) { 2431ac5507790a87810061a19dadec36eb328a222eaTao Liejun mConnected = false; 2441ac5507790a87810061a19dadec36eb328a222eaTao Liejun HeaderSet hs = new HeaderSet(); 2458eb70f8bdf4e8c970810b3400aba8d08d14ce222Martijn Coenen hs.setHeader(HeaderSet.COUNT, (long) numShares); 2461ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 2471ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = true; 2481ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 2491ac5507790a87810061a19dadec36eb328a222eaTao Liejun try { 2501ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCs.connect(hs); 251ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session created"); 2521ac5507790a87810061a19dadec36eb328a222eaTao Liejun mConnected = true; 2531ac5507790a87810061a19dadec36eb328a222eaTao Liejun } catch (IOException e) { 2541ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.e(TAG, "OBEX session connect error"); 25509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 25609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 25709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 25809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mWaitingForRemote = false; 25909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 26009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 26109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 26209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private void doSend() { 26309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 26409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int status = BluetoothShare.STATUS_SUCCESS; 26509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 26609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* connection is established too fast to get first mInfo */ 26709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly while (mFileInfo == null) { 26809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 26909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Thread.sleep(50); 27009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e) { 27109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_CANCELED; 27209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 27309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2741ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (!mConnected) { 2751ac5507790a87810061a19dadec36eb328a222eaTao Liejun // Obex connection error 2761ac5507790a87810061a19dadec36eb328a222eaTao Liejun status = BluetoothShare.STATUS_CONNECTION_ERROR; 2771ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 2781ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (status == BluetoothShare.STATUS_SUCCESS) { 27909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* do real send */ 28009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mFileInfo.mFileName != null) { 28109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = sendFile(mFileInfo); 28209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 28309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* this is invalid request */ 28409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = mFileInfo.mStatus; 28509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2861ac5507790a87810061a19dadec36eb328a222eaTao Liejun waitingForShare = true; 2871ac5507790a87810061a19dadec36eb328a222eaTao Liejun } else { 2881ac5507790a87810061a19dadec36eb328a222eaTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 28909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 29009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 29109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (status == BluetoothShare.STATUS_SUCCESS) { 29209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 29309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SHARE_COMPLETE; 29409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.obj = mInfo; 29509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 29609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 29709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 29809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SESSION_ERROR; 2991ac5507790a87810061a19dadec36eb328a222eaTao Liejun mInfo.mStatus = status; 30009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.obj = mInfo; 30109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 30209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 30309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 30409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 30509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* 30609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Validate this ShareInfo 30709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */ 30809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private BluetoothOppSendFileInfo processShareInfo() { 309ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Client thread processShareInfo() " + mInfo.mId); 31009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 311ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby BluetoothOppSendFileInfo fileInfo = BluetoothOppUtility.getSendFileInfo(mInfo.mUri); 3121ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (fileInfo.mFileName == null || fileInfo.mLength == 0) { 313ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "BluetoothOppSendFileInfo get invalid file"); 3146769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, fileInfo.mStatus); 31509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 31609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 317ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) { 31809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "Generate BluetoothOppSendFileInfo:"); 31909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "filename :" + fileInfo.mFileName); 32009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "length :" + fileInfo.mLength); 32109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "mimetype :" + fileInfo.mMimetype); 32209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 32309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 32409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly ContentValues updateValues = new ContentValues(); 32509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId); 32609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 32709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.FILENAME_HINT, fileInfo.mFileName); 32809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.TOTAL_BYTES, fileInfo.mLength); 32909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.MIMETYPE, fileInfo.mMimetype); 33009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 3316769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, null, null); 33209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 33309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 33409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly return fileInfo; 33509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 33609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 33709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private int sendFile(BluetoothOppSendFileInfo fileInfo) { 33809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly boolean error = false; 33909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int responseCode = -1; 340db94389c30d5ad5555a922d28868b119e1c6f2e1Andre Eisenbach int position = 0; 34109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int status = BluetoothShare.STATUS_SUCCESS; 34209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId); 34309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly ContentValues updateValues; 34409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly HeaderSet request; 3456769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun request = new HeaderSet(); 34609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly request.setHeader(HeaderSet.NAME, fileInfo.mFileName); 34709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly request.setHeader(HeaderSet.TYPE, fileInfo.mMimetype); 34809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 349ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby applyRemoteDeviceQuirks(request, mInfo.mDestination, fileInfo.mFileName); 350fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly 3516769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, BluetoothShare.STATUS_RUNNING); 35209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 35309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly request.setHeader(HeaderSet.LENGTH, fileInfo.mLength); 35409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly ClientOperation putOperation = null; 35509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly OutputStream outputStream = null; 35609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly InputStream inputStream = null; 35709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 35809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 35909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mWaitingForRemote = true; 36009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 36109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 362ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "put headerset for " + fileInfo.mFileName); 36309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly putOperation = (ClientOperation)mCs.put(request); 36409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 36509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_OBEX_DATA_ERROR; 3666769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 36709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 36809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "Error when put HeaderSet "); 36909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly error = true; 37009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 37109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 37209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mWaitingForRemote = false; 37309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 37409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 37509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 37609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 377ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "openOutputStream " + fileInfo.mFileName); 37809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly outputStream = putOperation.openOutputStream(); 37909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly inputStream = putOperation.openInputStream(); 38009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 38109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_OBEX_DATA_ERROR; 3826769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 38309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "Error when openOutputStream"); 38409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly error = true; 38509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 38609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 38709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 38809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues = new ContentValues(); 38909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.CURRENT_BYTES, 0); 39009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING); 3916769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, null, null); 39209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 39309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 39409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 39509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int readLength = 0; 39609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly boolean okToProceed = false; 39752236de777c23788df8147de15912a57e8bc36ddTao Liejun long timestamp = 0; 39809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int outputBufferSize = putOperation.getMaxPacketSize(); 39909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly byte[] buffer = new byte[outputBufferSize]; 40009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly BufferedInputStream a = new BufferedInputStream(fileInfo.mInputStream, 0x4000); 40109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4021ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (!mInterrupted && (position != fileInfo.mLength)) { 4030ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang readLength = readFully(a, buffer, outputBufferSize); 40409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4051ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCallback.sendMessageDelayed(mCallback 4061ac5507790a87810061a19dadec36eb328a222eaTao Liejun .obtainMessage(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT), 4071ac5507790a87810061a19dadec36eb328a222eaTao Liejun BluetoothOppObexSession.SESSION_TIMEOUT); 4081ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 4091ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = true; 41009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 4111ac5507790a87810061a19dadec36eb328a222eaTao Liejun 4121ac5507790a87810061a19dadec36eb328a222eaTao Liejun // first packet will block here 41309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly outputStream.write(buffer, 0, readLength); 41409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 41552236de777c23788df8147de15912a57e8bc36ddTao Liejun position += readLength; 41609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4171ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (position != fileInfo.mLength) { 4181ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT); 4191ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 4201ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = false; 42109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 4221ac5507790a87810061a19dadec36eb328a222eaTao Liejun } else { 4231ac5507790a87810061a19dadec36eb328a222eaTao Liejun // if file length is smaller than buffer size, only one packet 4241ac5507790a87810061a19dadec36eb328a222eaTao Liejun // so block point is here 4251ac5507790a87810061a19dadec36eb328a222eaTao Liejun outputStream.close(); 4261ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT); 4271ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 4281ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = false; 4291ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4301ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4311ac5507790a87810061a19dadec36eb328a222eaTao Liejun /* check remote accept or reject */ 4321ac5507790a87810061a19dadec36eb328a222eaTao Liejun responseCode = putOperation.getResponseCode(); 43309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4341ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (responseCode == ResponseCodes.OBEX_HTTP_CONTINUE 4351ac5507790a87810061a19dadec36eb328a222eaTao Liejun || responseCode == ResponseCodes.OBEX_HTTP_OK) { 436ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Remote accept"); 4371ac5507790a87810061a19dadec36eb328a222eaTao Liejun okToProceed = true; 4381ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues = new ContentValues(); 4391ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues.put(BluetoothShare.CURRENT_BYTES, position); 4401ac5507790a87810061a19dadec36eb328a222eaTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, null, 4411ac5507790a87810061a19dadec36eb328a222eaTao Liejun null); 44209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 4431ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.i(TAG, "Remote reject, Response code is " + responseCode); 4441ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4451ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4461ac5507790a87810061a19dadec36eb328a222eaTao Liejun 4471ac5507790a87810061a19dadec36eb328a222eaTao Liejun while (!mInterrupted && okToProceed && (position != fileInfo.mLength)) { 4481ac5507790a87810061a19dadec36eb328a222eaTao Liejun { 449ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) timestamp = System.currentTimeMillis(); 4501ac5507790a87810061a19dadec36eb328a222eaTao Liejun 4511ac5507790a87810061a19dadec36eb328a222eaTao Liejun readLength = a.read(buffer, 0, outputBufferSize); 4521ac5507790a87810061a19dadec36eb328a222eaTao Liejun outputStream.write(buffer, 0, readLength); 4531ac5507790a87810061a19dadec36eb328a222eaTao Liejun 45409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* check remote abort */ 45509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly responseCode = putOperation.getResponseCode(); 456ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Response code is " + responseCode); 4576769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun if (responseCode != ResponseCodes.OBEX_HTTP_CONTINUE 45809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly && responseCode != ResponseCodes.OBEX_HTTP_OK) { 45909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* abort happens */ 4601ac5507790a87810061a19dadec36eb328a222eaTao Liejun okToProceed = false; 4611ac5507790a87810061a19dadec36eb328a222eaTao Liejun } else { 4621ac5507790a87810061a19dadec36eb328a222eaTao Liejun position += readLength; 463ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) { 4641ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.v(TAG, "Sending file position = " + position 4651ac5507790a87810061a19dadec36eb328a222eaTao Liejun + " readLength " + readLength + " bytes took " 4661ac5507790a87810061a19dadec36eb328a222eaTao Liejun + (System.currentTimeMillis() - timestamp) + " ms"); 46709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 4681ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues = new ContentValues(); 4691ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues.put(BluetoothShare.CURRENT_BYTES, position); 4701ac5507790a87810061a19dadec36eb328a222eaTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, 4711ac5507790a87810061a19dadec36eb328a222eaTao Liejun null, null); 47209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 47309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 47409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 47509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4761ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (responseCode == ResponseCodes.OBEX_HTTP_FORBIDDEN 4771ac5507790a87810061a19dadec36eb328a222eaTao Liejun || responseCode == ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE) { 47852236de777c23788df8147de15912a57e8bc36ddTao Liejun Log.i(TAG, "Remote reject file " + fileInfo.mFileName + " length " 47952236de777c23788df8147de15912a57e8bc36ddTao Liejun + fileInfo.mLength); 48009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_FORBIDDEN; 48109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else if (responseCode == ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE) { 48252236de777c23788df8147de15912a57e8bc36ddTao Liejun Log.i(TAG, "Remote reject file type " + fileInfo.mMimetype); 48309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_NOT_ACCEPTABLE; 48409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else if (!mInterrupted && position == fileInfo.mLength) { 48552236de777c23788df8147de15912a57e8bc36ddTao Liejun Log.i(TAG, "SendFile finished send out file " + fileInfo.mFileName 48652236de777c23788df8147de15912a57e8bc36ddTao Liejun + " length " + fileInfo.mLength); 48709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly outputStream.close(); 48809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 48909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly error = true; 49009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_CANCELED; 49109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly putOperation.abort(); 49209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* interrupted */ 4931ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.i(TAG, "SendFile interrupted when send out file " + fileInfo.mFileName 4941ac5507790a87810061a19dadec36eb328a222eaTao Liejun + " at " + position + " of " + fileInfo.mLength); 49509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 49609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 49709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 498a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue handleSendException(e.toString()); 499a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue } catch (NullPointerException e) { 500a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue handleSendException(e.toString()); 501a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue } catch (IndexOutOfBoundsException e) { 502a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue handleSendException(e.toString()); 50309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } finally { 50409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 505ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby // Close InputStream and remove SendFileInfo from map 506ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby BluetoothOppUtility.closeSendFileInfo(mInfo.mUri); 50709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 50809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly responseCode = putOperation.getResponseCode(); 50909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (responseCode != -1) { 510ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Get response code " + responseCode); 51152236de777c23788df8147de15912a57e8bc36ddTao Liejun if (responseCode != ResponseCodes.OBEX_HTTP_OK) { 5121ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.i(TAG, "Response error code is " + responseCode); 51309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_UNHANDLED_OBEX_CODE; 51409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (responseCode == ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE) { 51509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_NOT_ACCEPTABLE; 51609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 5171ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (responseCode == ResponseCodes.OBEX_HTTP_FORBIDDEN 5181ac5507790a87810061a19dadec36eb328a222eaTao Liejun || responseCode == ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE) { 51909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_FORBIDDEN; 52009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 52109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 52209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 52352236de777c23788df8147de15912a57e8bc36ddTao Liejun // responseCode is -1, which means connection error 52409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_CONNECTION_ERROR; 52509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 52609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 52709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 5286769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 52909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 53009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (inputStream != null) { 53109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly inputStream.close(); 53209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (putOperation != null) { 53409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly putOperation.close(); 53509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 53709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "Error when closing stream after send"); 538ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi 539ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi // Socket has been closed due to the response timeout in the framework, 540ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi // mark the transfer as failure. 541ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi if (position != fileInfo.mLength) { 542ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi status = BluetoothShare.STATUS_FORBIDDEN; 543ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi Constants.updateShareStatus(mContext1, mInfo.mId, status); 544ae8997b870d52d6701813e6f3ff9d87a5a083bf3Pradeep Panigrahi } 54509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 54609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 54709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly return status; 54809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 54909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 550a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue private void handleSendException(String exception) { 551a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue Log.e(TAG, "Error when sending file: " + exception); 552a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT); 553a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue } 554a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue 55509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly @Override 55609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void interrupt() { 55709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly super.interrupt(); 55809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 55909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mWaitingForRemote) { 560ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Interrupted when waitingForRemote"); 56109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 5626769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mTransport1.close(); 56309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 56409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "mTransport.close error"); 56509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 56609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 56709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SHARE_INTERRUPTED; 5681ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (mInfo != null) { 5691ac5507790a87810061a19dadec36eb328a222eaTao Liejun msg.obj = mInfo; 5701ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 57109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 57209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 57309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 57409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 57509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 57609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 577ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby public static void applyRemoteDeviceQuirks(HeaderSet request, String address, String filename) { 578fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (address == null) { 579fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly return; 580fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 581fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (address.startsWith("00:04:48")) { 582fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // Poloroid Pogo 583fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // Rejects filenames with more than one '.'. Rename to '_'. 584fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // for example: 'a.b.jpg' -> 'a_b.jpg' 585fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // 'abc.jpg' NOT CHANGED 586fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly char[] c = filename.toCharArray(); 587fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly boolean firstDot = true; 588fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly boolean modified = false; 589fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly for (int i = c.length - 1; i >= 0; i--) { 590fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (c[i] == '.') { 591fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (!firstDot) { 592fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly modified = true; 593fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly c[i] = '_'; 594fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 595fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly firstDot = false; 596fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 597fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 598fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly 599fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (modified) { 600fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly String newFilename = new String(c); 601fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly request.setHeader(HeaderSet.NAME, newFilename); 602fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly Log.i(TAG, "Sending file \"" + filename + "\" as \"" + newFilename + 603fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly "\" to workaround Poloroid filename quirk"); 604fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 605fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 606fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 607fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly 60809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void unblock() { 6091ac5507790a87810061a19dadec36eb328a222eaTao Liejun // Not used for client case 61009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 61109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 61209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly} 613