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 8609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void start(Handler handler) { 87ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Start!"); 8809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCallback = handler; 8909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mThread = new ClientThread(mContext, mTransport); 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 1431ac5507790a87810061a19dadec36eb328a222eaTao Liejun public ClientThread(Context context, ObexTransport transport) { 1441ac5507790a87810061a19dadec36eb328a222eaTao Liejun super("BtOpp ClientThread"); 1451ac5507790a87810061a19dadec36eb328a222eaTao Liejun mContext1 = context; 1461ac5507790a87810061a19dadec36eb328a222eaTao Liejun mTransport1 = transport; 1471ac5507790a87810061a19dadec36eb328a222eaTao Liejun waitingForShare = true; 1481ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = false; 1491ac5507790a87810061a19dadec36eb328a222eaTao Liejun 1501ac5507790a87810061a19dadec36eb328a222eaTao Liejun PowerManager pm = (PowerManager)mContext1.getSystemService(Context.POWER_SERVICE); 1511ac5507790a87810061a19dadec36eb328a222eaTao Liejun wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 1521ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 1531ac5507790a87810061a19dadec36eb328a222eaTao Liejun 15409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void addShare(BluetoothOppShareInfo info) { 15509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mInfo = info; 15609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mFileInfo = processShareInfo(); 15709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly waitingForShare = false; 15809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 15909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 16009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly @Override 16109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void run() { 16209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 16309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 164ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "acquire partial WakeLock"); 16509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly wakeLock.acquire(); 16652236de777c23788df8147de15912a57e8bc36ddTao Liejun 16709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 16809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Thread.sleep(100); 16909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e1) { 170ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Client thread was interrupted (1), exiting"); 17109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mInterrupted = true; 17209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 17309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!mInterrupted) { 17409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly connect(); 17509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 1761ac5507790a87810061a19dadec36eb328a222eaTao Liejun 17709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly while (!mInterrupted) { 17809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!waitingForShare) { 17909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly doSend(); 18009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 18109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 182ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Client thread waiting for next share, sleep for " 1831ac5507790a87810061a19dadec36eb328a222eaTao Liejun + sSleepTime); 1841ac5507790a87810061a19dadec36eb328a222eaTao Liejun Thread.sleep(sSleepTime); 18509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e) { 18609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 18709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 18809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 18909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 19009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly disconnect(); 1916769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun 1921ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (wakeLock.isHeld()) { 193ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "release partial WakeLock"); 1941ac5507790a87810061a19dadec36eb328a222eaTao Liejun wakeLock.release(); 19509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 19609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 19709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SESSION_COMPLETE; 19809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.obj = mInfo; 19909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 2001ac5507790a87810061a19dadec36eb328a222eaTao Liejun 20109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 20209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 20309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private void disconnect() { 20409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 20509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mCs != null) { 20609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCs.disconnect(null); 20709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 20809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCs = null; 209ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session disconnected"); 21009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 2111ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.w(TAG, "OBEX session disconnect error" + e); 21209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 21309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 21409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mCs != null) { 215ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session close mCs"); 21609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mCs.close(); 217ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session closed"); 21809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 21909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 2201ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.w(TAG, "OBEX session close error" + e); 22109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2226769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun if (mTransport1 != null) { 22309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 2246769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mTransport1.close(); 22509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 22609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "mTransport.close error"); 22709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 22809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 22909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 23009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 23109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 23209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private void connect() { 233ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "Create ClientSession with transport " + mTransport1.toString()); 2346769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun try { 2356769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mCs = new ClientSession(mTransport1); 2361ac5507790a87810061a19dadec36eb328a222eaTao Liejun mConnected = true; 2376769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun } catch (IOException e1) { 2386769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Log.e(TAG, "OBEX session create error"); 23909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2401ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (mConnected) { 2411ac5507790a87810061a19dadec36eb328a222eaTao Liejun mConnected = false; 2421ac5507790a87810061a19dadec36eb328a222eaTao Liejun HeaderSet hs = new HeaderSet(); 2431ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 2441ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = true; 2451ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 2461ac5507790a87810061a19dadec36eb328a222eaTao Liejun try { 2471ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCs.connect(hs); 248ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (D) Log.d(TAG, "OBEX session created"); 2491ac5507790a87810061a19dadec36eb328a222eaTao Liejun mConnected = true; 2501ac5507790a87810061a19dadec36eb328a222eaTao Liejun } catch (IOException e) { 2511ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.e(TAG, "OBEX session connect error"); 25209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 25309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 25409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 25509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mWaitingForRemote = false; 25609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 25709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 25809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 25909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private void doSend() { 26009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 26109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int status = BluetoothShare.STATUS_SUCCESS; 26209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 26309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* connection is established too fast to get first mInfo */ 26409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly while (mFileInfo == null) { 26509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 26609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Thread.sleep(50); 26709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (InterruptedException e) { 26809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_CANCELED; 26909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 27009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2711ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (!mConnected) { 2721ac5507790a87810061a19dadec36eb328a222eaTao Liejun // Obex connection error 2731ac5507790a87810061a19dadec36eb328a222eaTao Liejun status = BluetoothShare.STATUS_CONNECTION_ERROR; 2741ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 2751ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (status == BluetoothShare.STATUS_SUCCESS) { 27609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* do real send */ 27709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mFileInfo.mFileName != null) { 27809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = sendFile(mFileInfo); 27909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 28009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* this is invalid request */ 28109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = mFileInfo.mStatus; 28209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 2831ac5507790a87810061a19dadec36eb328a222eaTao Liejun waitingForShare = true; 2841ac5507790a87810061a19dadec36eb328a222eaTao Liejun } else { 2851ac5507790a87810061a19dadec36eb328a222eaTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 28609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 28709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 28809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (status == BluetoothShare.STATUS_SUCCESS) { 28909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 29009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SHARE_COMPLETE; 29109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.obj = mInfo; 29209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 29309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 29409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 29509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SESSION_ERROR; 2961ac5507790a87810061a19dadec36eb328a222eaTao Liejun mInfo.mStatus = status; 29709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.obj = mInfo; 29809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 29909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 30009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 30109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 30209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* 30309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Validate this ShareInfo 30409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */ 30509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private BluetoothOppSendFileInfo processShareInfo() { 306ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Client thread processShareInfo() " + mInfo.mId); 30709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 308ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby BluetoothOppSendFileInfo fileInfo = BluetoothOppUtility.getSendFileInfo(mInfo.mUri); 3091ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (fileInfo.mFileName == null || fileInfo.mLength == 0) { 310ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "BluetoothOppSendFileInfo get invalid file"); 3116769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, fileInfo.mStatus); 31209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 31309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 314ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) { 31509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "Generate BluetoothOppSendFileInfo:"); 31609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "filename :" + fileInfo.mFileName); 31709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "length :" + fileInfo.mLength); 31809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.v(TAG, "mimetype :" + fileInfo.mMimetype); 31909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 32009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 32109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly ContentValues updateValues = new ContentValues(); 32209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId); 32309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 32409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.FILENAME_HINT, fileInfo.mFileName); 32509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.TOTAL_BYTES, fileInfo.mLength); 32609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.MIMETYPE, fileInfo.mMimetype); 32709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 3286769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, null, null); 32909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 33009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 33109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly return fileInfo; 33209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 33309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 33409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly private int sendFile(BluetoothOppSendFileInfo fileInfo) { 33509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly boolean error = false; 33609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int responseCode = -1; 33709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int status = BluetoothShare.STATUS_SUCCESS; 33809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId); 33909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly ContentValues updateValues; 34009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly HeaderSet request; 3416769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun request = new HeaderSet(); 34209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly request.setHeader(HeaderSet.NAME, fileInfo.mFileName); 34309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly request.setHeader(HeaderSet.TYPE, fileInfo.mMimetype); 34409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 345ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby applyRemoteDeviceQuirks(request, mInfo.mDestination, fileInfo.mFileName); 346fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly 3476769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, BluetoothShare.STATUS_RUNNING); 34809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 34909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly request.setHeader(HeaderSet.LENGTH, fileInfo.mLength); 35009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly ClientOperation putOperation = null; 35109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly OutputStream outputStream = null; 35209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly InputStream inputStream = null; 35309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 35409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 35509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mWaitingForRemote = true; 35609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 35709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 358ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "put headerset for " + fileInfo.mFileName); 35909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly putOperation = (ClientOperation)mCs.put(request); 36009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 36109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_OBEX_DATA_ERROR; 3626769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 36309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 36409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "Error when put HeaderSet "); 36509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly error = true; 36609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 36709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 36809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly mWaitingForRemote = false; 36909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 37009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 37109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 37209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 373ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "openOutputStream " + fileInfo.mFileName); 37409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly outputStream = putOperation.openOutputStream(); 37509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly inputStream = putOperation.openInputStream(); 37609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 37709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_OBEX_DATA_ERROR; 3786769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 37909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "Error when openOutputStream"); 38009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly error = true; 38109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 38209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 38309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 38409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues = new ContentValues(); 38509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.CURRENT_BYTES, 0); 38609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING); 3876769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, null, null); 38809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 38909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 39009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 39109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int position = 0; 39209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int readLength = 0; 39309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly boolean okToProceed = false; 39452236de777c23788df8147de15912a57e8bc36ddTao Liejun long timestamp = 0; 39509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly int outputBufferSize = putOperation.getMaxPacketSize(); 39609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly byte[] buffer = new byte[outputBufferSize]; 39709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly BufferedInputStream a = new BufferedInputStream(fileInfo.mInputStream, 0x4000); 39809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 3991ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (!mInterrupted && (position != fileInfo.mLength)) { 4000ac98162ff293fdaa23f93f9839aaad5428af537Chih-Chung Chang readLength = readFully(a, buffer, outputBufferSize); 40109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4021ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCallback.sendMessageDelayed(mCallback 4031ac5507790a87810061a19dadec36eb328a222eaTao Liejun .obtainMessage(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT), 4041ac5507790a87810061a19dadec36eb328a222eaTao Liejun BluetoothOppObexSession.SESSION_TIMEOUT); 4051ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 4061ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = true; 40709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 4081ac5507790a87810061a19dadec36eb328a222eaTao Liejun 4091ac5507790a87810061a19dadec36eb328a222eaTao Liejun // first packet will block here 41009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly outputStream.write(buffer, 0, readLength); 41109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 41252236de777c23788df8147de15912a57e8bc36ddTao Liejun position += readLength; 41309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4141ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (position != fileInfo.mLength) { 4151ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT); 4161ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 4171ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = false; 41809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 4191ac5507790a87810061a19dadec36eb328a222eaTao Liejun } else { 4201ac5507790a87810061a19dadec36eb328a222eaTao Liejun // if file length is smaller than buffer size, only one packet 4211ac5507790a87810061a19dadec36eb328a222eaTao Liejun // so block point is here 4221ac5507790a87810061a19dadec36eb328a222eaTao Liejun outputStream.close(); 4231ac5507790a87810061a19dadec36eb328a222eaTao Liejun mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT); 4241ac5507790a87810061a19dadec36eb328a222eaTao Liejun synchronized (this) { 4251ac5507790a87810061a19dadec36eb328a222eaTao Liejun mWaitingForRemote = false; 4261ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4271ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4281ac5507790a87810061a19dadec36eb328a222eaTao Liejun /* check remote accept or reject */ 4291ac5507790a87810061a19dadec36eb328a222eaTao Liejun responseCode = putOperation.getResponseCode(); 43009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4311ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (responseCode == ResponseCodes.OBEX_HTTP_CONTINUE 4321ac5507790a87810061a19dadec36eb328a222eaTao Liejun || responseCode == ResponseCodes.OBEX_HTTP_OK) { 433ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Remote accept"); 4341ac5507790a87810061a19dadec36eb328a222eaTao Liejun okToProceed = true; 4351ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues = new ContentValues(); 4361ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues.put(BluetoothShare.CURRENT_BYTES, position); 4371ac5507790a87810061a19dadec36eb328a222eaTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, null, 4381ac5507790a87810061a19dadec36eb328a222eaTao Liejun null); 43909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 4401ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.i(TAG, "Remote reject, Response code is " + responseCode); 4411ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4421ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 4431ac5507790a87810061a19dadec36eb328a222eaTao Liejun 4441ac5507790a87810061a19dadec36eb328a222eaTao Liejun while (!mInterrupted && okToProceed && (position != fileInfo.mLength)) { 4451ac5507790a87810061a19dadec36eb328a222eaTao Liejun { 446ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) timestamp = System.currentTimeMillis(); 4471ac5507790a87810061a19dadec36eb328a222eaTao Liejun 4481ac5507790a87810061a19dadec36eb328a222eaTao Liejun readLength = a.read(buffer, 0, outputBufferSize); 4491ac5507790a87810061a19dadec36eb328a222eaTao Liejun outputStream.write(buffer, 0, readLength); 4501ac5507790a87810061a19dadec36eb328a222eaTao Liejun 45109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* check remote abort */ 45209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly responseCode = putOperation.getResponseCode(); 453ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Response code is " + responseCode); 4546769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun if (responseCode != ResponseCodes.OBEX_HTTP_CONTINUE 45509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly && responseCode != ResponseCodes.OBEX_HTTP_OK) { 45609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* abort happens */ 4571ac5507790a87810061a19dadec36eb328a222eaTao Liejun okToProceed = false; 4581ac5507790a87810061a19dadec36eb328a222eaTao Liejun } else { 4591ac5507790a87810061a19dadec36eb328a222eaTao Liejun position += readLength; 460ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) { 4611ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.v(TAG, "Sending file position = " + position 4621ac5507790a87810061a19dadec36eb328a222eaTao Liejun + " readLength " + readLength + " bytes took " 4631ac5507790a87810061a19dadec36eb328a222eaTao Liejun + (System.currentTimeMillis() - timestamp) + " ms"); 46409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 4651ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues = new ContentValues(); 4661ac5507790a87810061a19dadec36eb328a222eaTao Liejun updateValues.put(BluetoothShare.CURRENT_BYTES, position); 4671ac5507790a87810061a19dadec36eb328a222eaTao Liejun mContext1.getContentResolver().update(contentUri, updateValues, 4681ac5507790a87810061a19dadec36eb328a222eaTao Liejun null, null); 46909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 47009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 47109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 47209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 4731ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (responseCode == ResponseCodes.OBEX_HTTP_FORBIDDEN 4741ac5507790a87810061a19dadec36eb328a222eaTao Liejun || responseCode == ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE) { 47552236de777c23788df8147de15912a57e8bc36ddTao Liejun Log.i(TAG, "Remote reject file " + fileInfo.mFileName + " length " 47652236de777c23788df8147de15912a57e8bc36ddTao Liejun + fileInfo.mLength); 47709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_FORBIDDEN; 47809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else if (responseCode == ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE) { 47952236de777c23788df8147de15912a57e8bc36ddTao Liejun Log.i(TAG, "Remote reject file type " + fileInfo.mMimetype); 48009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_NOT_ACCEPTABLE; 48109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else if (!mInterrupted && position == fileInfo.mLength) { 48252236de777c23788df8147de15912a57e8bc36ddTao Liejun Log.i(TAG, "SendFile finished send out file " + fileInfo.mFileName 48352236de777c23788df8147de15912a57e8bc36ddTao Liejun + " length " + fileInfo.mLength); 48409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly outputStream.close(); 48509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 48609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly error = true; 48709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_CANCELED; 48809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly putOperation.abort(); 48909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly /* interrupted */ 4901ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.i(TAG, "SendFile interrupted when send out file " + fileInfo.mFileName 4911ac5507790a87810061a19dadec36eb328a222eaTao Liejun + " at " + position + " of " + fileInfo.mLength); 49209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 49309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 49409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 495a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue handleSendException(e.toString()); 496a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue } catch (NullPointerException e) { 497a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue handleSendException(e.toString()); 498a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue } catch (IndexOutOfBoundsException e) { 499a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue handleSendException(e.toString()); 50009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } finally { 50109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 502ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby // Close InputStream and remove SendFileInfo from map 503ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby BluetoothOppUtility.closeSendFileInfo(mInfo.mUri); 50409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (!error) { 50509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly responseCode = putOperation.getResponseCode(); 50609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (responseCode != -1) { 507ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Get response code " + responseCode); 50852236de777c23788df8147de15912a57e8bc36ddTao Liejun if (responseCode != ResponseCodes.OBEX_HTTP_OK) { 5091ac5507790a87810061a19dadec36eb328a222eaTao Liejun Log.i(TAG, "Response error code is " + responseCode); 51009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_UNHANDLED_OBEX_CODE; 51109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (responseCode == ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE) { 51209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_NOT_ACCEPTABLE; 51309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 5141ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (responseCode == ResponseCodes.OBEX_HTTP_FORBIDDEN 5151ac5507790a87810061a19dadec36eb328a222eaTao Liejun || responseCode == ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE) { 51609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_FORBIDDEN; 51709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 51809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 51909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } else { 52052236de777c23788df8147de15912a57e8bc36ddTao Liejun // responseCode is -1, which means connection error 52109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly status = BluetoothShare.STATUS_CONNECTION_ERROR; 52209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 52309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 52409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 5256769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun Constants.updateShareStatus(mContext1, mInfo.mId, status); 52609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 52709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (inputStream != null) { 52809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly inputStream.close(); 52909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (putOperation != null) { 53109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly putOperation.close(); 53209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 53409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "Error when closing stream after send"); 53509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly return status; 53809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 53909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 540a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue private void handleSendException(String exception) { 541a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue Log.e(TAG, "Error when sending file: " + exception); 542a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue int status = BluetoothShare.STATUS_OBEX_DATA_ERROR; 543a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue Constants.updateShareStatus(mContext1, mInfo.mId, status); 544a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT); 545a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue } 546a4508589f298c67fda54c344760ae39f0f375c11Lixin Yue 54709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly @Override 54809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void interrupt() { 54909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly super.interrupt(); 55009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly synchronized (this) { 55109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly if (mWaitingForRemote) { 552ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly if (V) Log.v(TAG, "Interrupted when waitingForRemote"); 55309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly try { 5546769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun mTransport1.close(); 55509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } catch (IOException e) { 55609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Log.e(TAG, "mTransport.close error"); 55709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 55809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly Message msg = Message.obtain(mCallback); 55909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.what = BluetoothOppObexSession.MSG_SHARE_INTERRUPTED; 5601ac5507790a87810061a19dadec36eb328a222eaTao Liejun if (mInfo != null) { 5611ac5507790a87810061a19dadec36eb328a222eaTao Liejun msg.obj = mInfo; 5621ac5507790a87810061a19dadec36eb328a222eaTao Liejun } 56309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly msg.sendToTarget(); 56409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 56509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 56609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 56709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 56809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 569ee52ddf33a0ce2cf89cc028136f60ae600c45de5Jake Hamby public static void applyRemoteDeviceQuirks(HeaderSet request, String address, String filename) { 570fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (address == null) { 571fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly return; 572fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 573fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (address.startsWith("00:04:48")) { 574fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // Poloroid Pogo 575fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // Rejects filenames with more than one '.'. Rename to '_'. 576fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // for example: 'a.b.jpg' -> 'a_b.jpg' 577fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly // 'abc.jpg' NOT CHANGED 578fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly char[] c = filename.toCharArray(); 579fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly boolean firstDot = true; 580fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly boolean modified = false; 581fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly for (int i = c.length - 1; i >= 0; i--) { 582fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (c[i] == '.') { 583fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (!firstDot) { 584fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly modified = true; 585fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly c[i] = '_'; 586fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 587fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly firstDot = false; 588fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 589fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 590fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly 591fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly if (modified) { 592fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly String newFilename = new String(c); 593fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly request.setHeader(HeaderSet.NAME, newFilename); 594fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly Log.i(TAG, "Sending file \"" + filename + "\" as \"" + newFilename + 595fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly "\" to workaround Poloroid filename quirk"); 596fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 597fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 598fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly } 599fa5d402906010cd17c8ed7de0dbcbfdcb78dab20Nick Pelly 60009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly public void unblock() { 6011ac5507790a87810061a19dadec36eb328a222eaTao Liejun // Not used for client case 60209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly } 60309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly 60409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly} 605