BluetoothOppObexServerSession.java revision 32e47df203390052c1ef771d78b22fc4aa5f9e72
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 java.io.BufferedOutputStream;
3609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.File;
3709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.IOException;
3809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.InputStream;
3909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
4009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.ContentValues;
4109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Context;
4209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Intent;
4309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.net.Uri;
4409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Handler;
4509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Message;
4652236de777c23788df8147de15912a57e8bc36ddTao Liejunimport android.os.PowerManager;
4752236de777c23788df8147de15912a57e8bc36ddTao Liejunimport android.os.PowerManager.WakeLock;
4809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.util.Log;
4909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.webkit.MimeTypeMap;
5009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
5109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.HeaderSet;
5209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ObexTransport;
5309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.Operation;
5409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ResponseCodes;
5509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ServerRequestHandler;
5609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ServerSession;
5709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
5809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/**
5909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * This class runs as an OBEX server
6009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */
6109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypublic class BluetoothOppObexServerSession extends ServerRequestHandler implements
6209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BluetoothOppObexSession {
6309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
64ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final String TAG = "BtOppObexServer";
65ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final boolean D = Constants.DEBUG;
66ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final boolean V = Constants.VERBOSE;
6709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
6809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private ObexTransport mTransport;
6909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private Context mContext;
7109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private Handler mCallback = null;
7309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* status when server is blocking for user/auto confirmation */
7509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean mServerBlocking = true;
7609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* the current transfer info */
7809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppShareInfo mInfo;
7909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* info id when we insert the record */
8109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int mLocalShareInfoId;
8209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int mAccepted = BluetoothShare.USER_CONFIRMATION_PENDING;
8409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean mInterrupted = false;
8609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private ServerSession mSession;
8809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private long mTimestamp;
9009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppReceiveFileInfo mFileInfo;
9209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9352236de777c23788df8147de15912a57e8bc36ddTao Liejun    private WakeLock mWakeLock;
9452236de777c23788df8147de15912a57e8bc36ddTao Liejun
9552236de777c23788df8147de15912a57e8bc36ddTao Liejun    private WakeLock mPartialWakeLock;
9652236de777c23788df8147de15912a57e8bc36ddTao Liejun
971ac5507790a87810061a19dadec36eb328a222eaTao Liejun    boolean mTimeoutMsgSent = false;
981ac5507790a87810061a19dadec36eb328a222eaTao Liejun
9909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public BluetoothOppObexServerSession(Context context, ObexTransport transport) {
10009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mContext = context;
10109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mTransport = transport;
10252236de777c23788df8147de15912a57e8bc36ddTao Liejun        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
10352236de777c23788df8147de15912a57e8bc36ddTao Liejun        mWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP
10452236de777c23788df8147de15912a57e8bc36ddTao Liejun                | PowerManager.ON_AFTER_RELEASE, TAG);
10552236de777c23788df8147de15912a57e8bc36ddTao Liejun        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
10609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
10709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void unblock() {
10909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mServerBlocking = false;
11009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
11109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
11309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Called when connection is accepted from remote, to retrieve the first
11409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Header then wait for user confirmation
11509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
11609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void preStart() {
117ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "acquire full WakeLock");
11852236de777c23788df8147de15912a57e8bc36ddTao Liejun        mWakeLock.acquire();
11909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        try {
120ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly            if (D) Log.d(TAG, "Create ServerSession with transport " + mTransport.toString());
12109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mSession = new ServerSession(mTransport, this, null);
12209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } catch (IOException e) {
12309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "Create server session error" + e);
12409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
12509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
12609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
12809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Called from BluetoothOppTransfer to start the "Transfer"
12909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
13009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void start(Handler handler) {
131ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "Start!");
13209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mCallback = handler;
13309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
13409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
13509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
13609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
1376769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun     * Called from BluetoothOppTransfer to cancel the "Transfer" Otherwise,
1386769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun     * server should end by itself.
13909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
14009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void stop() {
14109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
14209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * TODO now we implement in a tough way, just close the socket.
14309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * maybe need nice way
14409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
145ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "Stop!");
14609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mInterrupted = true;
14709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mSession != null) {
14809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
14909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mSession.close();
15009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mTransport.close();
15109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (IOException e) {
15209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.e(TAG, "close mTransport error" + e);
15309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
15409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
1551ac5507790a87810061a19dadec36eb328a222eaTao Liejun        mCallback = null;
1561ac5507790a87810061a19dadec36eb328a222eaTao Liejun        mSession = null;
15709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
15809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
15909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void addShare(BluetoothOppShareInfo info) {
160ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "addShare for id " + info.mId);
16109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mInfo = info;
16209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mFileInfo = processShareInfo();
16309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
16409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
16509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
16609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public int onPut(Operation op) {
167ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "onPut " + op.toString());
16809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        HeaderSet request;
16909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        String name, mimeType;
17009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Long length;
17109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
17209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int obexResponse = ResponseCodes.OBEX_HTTP_OK;
17309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
17409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /**
17509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * For multiple objects, reject further objects after user deny the
17609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * first one
17709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
17809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mAccepted == BluetoothShare.USER_CONFIRMATION_DENIED) {
17909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return ResponseCodes.OBEX_HTTP_FORBIDDEN;
18009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
18109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
18209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        try {
18309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            boolean pre_reject = false;
1846769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun            request = op.getReceivedHeader();
185ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly            if (V) Constants.logHeader(request);
18609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            name = (String)request.getHeader(HeaderSet.NAME);
18709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            length = (Long)request.getHeader(HeaderSet.LENGTH);
18809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mimeType = (String)request.getHeader(HeaderSet.TYPE);
18909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
19009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (length == 0) {
191ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.w(TAG, "length is 0, reject the transfer");
19209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                pre_reject = true;
19309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_LENGTH_REQUIRED;
19409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
19509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
19609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (name == null || name.equals("")) {
197ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.w(TAG, "name is null or empty, reject the transfer");
19809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                pre_reject = true;
19909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
20009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
20109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
20209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (!pre_reject) {
20309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /* first we look for Mimetype in Android map */
20409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                String extension, type;
20509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                int dotIndex = name.indexOf('.');
20609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (dotIndex < 0) {
207ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (D) Log.w(TAG, "There is no file extension, reject the transfer");
20809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    pre_reject = true;
20909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    obexResponse = ResponseCodes.OBEX_HTTP_BAD_REQUEST;
21009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
2111ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    extension = name.substring(dotIndex + 1).toLowerCase();
21209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    MimeTypeMap map = MimeTypeMap.getSingleton();
21309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    type = map.getMimeTypeFromExtension(extension);
214ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) Log.v(TAG, "Mimetype guessed from extension " + extension + " is " + type);
21509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (type != null) {
21609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mimeType = type;
21709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
21809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else {
21909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (mimeType == null) {
220ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                            if (D) Log.w(TAG, "Can't get mimetype, reject the transfer");
22109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            pre_reject = true;
222239bc526513429995c61c4148c105725c395b1a9Jackson Fan                            obexResponse = ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE;
22309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
22409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
22509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (mimeType != null) {
22609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mimeType = mimeType.toLowerCase();
22709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
22809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
22909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
23009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
23109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (!pre_reject
23209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    && (mimeType == null || Constants.mimeTypeMatches(mimeType,
23309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Constants.UNACCEPTABLE_SHARE_INBOUND_TYPES))) {
234ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.w(TAG, "mimeType is null or in unacceptable list, reject the transfer");
23509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                pre_reject = true;
23609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_UNSUPPORTED_TYPE;
23709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
23809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
23909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (pre_reject && obexResponse != ResponseCodes.OBEX_HTTP_OK) {
2401ac5507790a87810061a19dadec36eb328a222eaTao Liejun                // some bad implemented client won't send disconnect
24109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                return obexResponse;
24209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
24309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
24409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } catch (IOException e) {
24509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "get getReceivedHeaders error " + e);
24609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return ResponseCodes.OBEX_HTTP_BAD_REQUEST;
24709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
24809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
24909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        ContentValues values = new ContentValues();
25009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.FILENAME_HINT, name);
25209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.TOTAL_BYTES, length.intValue());
25309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.MIMETYPE, mimeType);
25409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mTransport instanceof BluetoothOppRfcommTransport) {
25609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            String a = ((BluetoothOppRfcommTransport)mTransport).getRemoteAddress();
25709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            values.put(BluetoothShare.DESTINATION, a);
25809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else {
25909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            values.put(BluetoothShare.DESTINATION, "FF:FF:FF:00:00:00");
26009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
26109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
26209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_INBOUND);
26309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        values.put(BluetoothShare.TIMESTAMP, mTimestamp);
26409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
26509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        boolean needConfirm = true;
26609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /** It's not first put if !serverBlocking, so we auto accept it */
26709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!mServerBlocking) {
26809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            values.put(BluetoothShare.USER_CONFIRMATION,
26909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED);
27009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            needConfirm = false;
27109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
27209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
27309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Uri contentUri = mContext.getContentResolver().insert(BluetoothShare.CONTENT_URI, values);
27409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mLocalShareInfoId = Integer.parseInt(contentUri.getPathSegments().get(1));
27509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
27609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (needConfirm) {
27709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Intent in = new Intent(BluetoothShare.INCOMING_FILE_CONFIRMATION_REQUEST_ACTION);
27809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            in.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
27909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mContext.sendBroadcast(in);
28009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
28109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
282ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Log.v(TAG, "insert contentUri: " + contentUri);
28309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "mLocalShareInfoId = " + mLocalShareInfoId);
28409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
285ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Log.v(TAG, "acquire partial WakeLock");
2861ac5507790a87810061a19dadec36eb328a222eaTao Liejun        if (mWakeLock.isHeld()) {
28752236de777c23788df8147de15912a57e8bc36ddTao Liejun            mPartialWakeLock.acquire();
28852236de777c23788df8147de15912a57e8bc36ddTao Liejun            mWakeLock.release();
28952236de777c23788df8147de15912a57e8bc36ddTao Liejun        }
2901ac5507790a87810061a19dadec36eb328a222eaTao Liejun
29109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mServerBlocking = true;
2921ac5507790a87810061a19dadec36eb328a222eaTao Liejun
29309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        synchronized (this) {
29409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
295df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun
29609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                while (mServerBlocking) {
29709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    wait(1000);
2981ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    if (mCallback != null && !mTimeoutMsgSent) {
29909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mCallback.sendMessageDelayed(mCallback
30009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                .obtainMessage(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT),
30109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                BluetoothOppObexSession.SESSION_TIMEOUT);
3021ac5507790a87810061a19dadec36eb328a222eaTao Liejun                        mTimeoutMsgSent = true;
303ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                        if (V) Log.v(TAG, "MSG_CONNECT_TIMEOUT sent");
30409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
30509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
30609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (InterruptedException e) {
307ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (V) Log.v(TAG, "Interrupted in onPut blocking");
30809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
30909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
310ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "Server unblocked ");
3111ac5507790a87810061a19dadec36eb328a222eaTao Liejun        if (mCallback != null && mTimeoutMsgSent) {
3126769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun            mCallback.removeMessages(BluetoothOppObexSession.MSG_CONNECT_TIMEOUT);
3136769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        }
31409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
31509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /* we should have mInfo now */
31609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
31709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
31809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * TODO check if this mInfo match the one that we insert before server
31909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * blocking? just to make sure no error happens
32009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
32109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mInfo.mId != mLocalShareInfoId) {
32209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "Unexpected error!");
32309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
32409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mAccepted = mInfo.mConfirm;
32509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
326ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Log.v(TAG, "after confirm: userAccepted=" + mAccepted);
32709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int status = BluetoothShare.STATUS_SUCCESS;
32809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
32909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mAccepted == BluetoothShare.USER_CONFIRMATION_CONFIRMED
330df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun                || mAccepted == BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED) {
33109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /* Confirm or auto-confirm */
33209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
33309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mFileInfo.mFileName == null) {
33409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = mFileInfo.mStatus;
33509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /* TODO need to check if this line is correct */
33609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mInfo.mStatus = mFileInfo.mStatus;
33709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Constants.updateShareStatus(mContext, mInfo.mId, status);
33809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                obexResponse = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
33909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
34009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
34109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
34209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mFileInfo.mFileName != null) {
34309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
34409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                ContentValues updateValues = new ContentValues();
34509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId);
34609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                updateValues.put(BluetoothShare._DATA, mFileInfo.mFileName);
34709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                updateValues.put(BluetoothShare.STATUS, BluetoothShare.STATUS_RUNNING);
34809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mContext.getContentResolver().update(contentUri, updateValues, null, null);
34909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
35009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = receiveFile(mFileInfo, op);
35109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /*
35209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * TODO map status to obex response code
35309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 */
35409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (status != BluetoothShare.STATUS_SUCCESS) {
35509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    obexResponse = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
35609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
35709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Constants.updateShareStatus(mContext, mInfo.mId, status);
35809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
35909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
36009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (status == BluetoothShare.STATUS_SUCCESS) {
36109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Message msg = Message.obtain(mCallback, BluetoothOppObexSession.MSG_SHARE_COMPLETE);
36209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                msg.obj = mInfo;
36309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                msg.sendToTarget();
36409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
3651ac5507790a87810061a19dadec36eb328a222eaTao Liejun                if (mCallback != null) {
3661ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    Message msg = Message.obtain(mCallback,
3671ac5507790a87810061a19dadec36eb328a222eaTao Liejun                            BluetoothOppObexSession.MSG_SESSION_ERROR);
3681ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    mInfo.mStatus = status;
3691ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    msg.obj = mInfo;
3701ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    msg.sendToTarget();
3711ac5507790a87810061a19dadec36eb328a222eaTao Liejun                }
37209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
37309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else if (mAccepted == BluetoothShare.USER_CONFIRMATION_DENIED
37409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                || mAccepted == BluetoothShare.USER_CONFIRMATION_TIMEOUT) {
37509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /* user actively deny the inbound transfer */
37609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /*
37709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Note There is a question: what's next if user deny the first obj?
37809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Option 1 :continue prompt for next objects
37909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Option 2 :reject next objects and finish the session
38009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * Now we take option 2:
38109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             */
38252236de777c23788df8147de15912a57e8bc36ddTao Liejun
38352236de777c23788df8147de15912a57e8bc36ddTao Liejun            Log.i(TAG, "Rejected incoming request");
3841ac5507790a87810061a19dadec36eb328a222eaTao Liejun            if (mFileInfo.mFileName != null) {
3851ac5507790a87810061a19dadec36eb328a222eaTao Liejun                try {
3861ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    mFileInfo.mOutputStream.close();
3871ac5507790a87810061a19dadec36eb328a222eaTao Liejun                } catch (IOException e) {
3881ac5507790a87810061a19dadec36eb328a222eaTao Liejun                    Log.e(TAG, "error close file stream");
3891ac5507790a87810061a19dadec36eb328a222eaTao Liejun                }
3901ac5507790a87810061a19dadec36eb328a222eaTao Liejun                new File(mFileInfo.mFileName).delete();
3911ac5507790a87810061a19dadec36eb328a222eaTao Liejun            }
3921ac5507790a87810061a19dadec36eb328a222eaTao Liejun            // set status as local cancel
3931ac5507790a87810061a19dadec36eb328a222eaTao Liejun            status = BluetoothShare.STATUS_CANCELED;
39409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Constants.updateShareStatus(mContext, mInfo.mId, status);
39509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            obexResponse = ResponseCodes.OBEX_HTTP_FORBIDDEN;
3961ac5507790a87810061a19dadec36eb328a222eaTao Liejun
39709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Message msg = Message.obtain(mCallback);
39809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.what = BluetoothOppObexSession.MSG_SHARE_INTERRUPTED;
3991ac5507790a87810061a19dadec36eb328a222eaTao Liejun            mInfo.mStatus = status;
40009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.obj = mInfo;
40109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.sendToTarget();
40209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
40309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return obexResponse;
40409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
40509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
40609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int receiveFile(BluetoothOppReceiveFileInfo fileInfo, Operation op) {
40709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
40809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * implement receive file
40909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
41009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int status = -1;
41109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BufferedOutputStream bos = null;
41209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
41309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        InputStream is = null;
41409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        boolean error = false;
41509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        try {
41609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            is = op.openInputStream();
41709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } catch (IOException e1) {
41809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "Error when openInputStream");
41909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            status = BluetoothShare.STATUS_OBEX_DATA_ERROR;
42009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            error = true;
42109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
42209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
42309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + mInfo.mId);
42409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
42509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!error) {
42609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            ContentValues updateValues = new ContentValues();
42709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            updateValues.put(BluetoothShare._DATA, fileInfo.mFileName);
42809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mContext.getContentResolver().update(contentUri, updateValues, null, null);
42909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
43009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
43109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int position = 0;
43209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!error) {
4331ac5507790a87810061a19dadec36eb328a222eaTao Liejun            bos = new BufferedOutputStream(fileInfo.mOutputStream, 0x10000);
43409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
43509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
43609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!error) {
43709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int outputBufferSize = op.getMaxPacketSize();
43809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            byte[] b = new byte[outputBufferSize];
43909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int readLength = 0;
44052236de777c23788df8147de15912a57e8bc36ddTao Liejun            long timestamp = 0;
44109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
44209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                while ((!mInterrupted) && (position != fileInfo.mLength)) {
44309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
444ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) timestamp = System.currentTimeMillis();
44509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
44609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    readLength = is.read(b);
44709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
44809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (readLength == -1) {
449ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                        if (D) Log.d(TAG, "Receive file reached stream end at position" + position);
45009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        break;
45109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
45209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
45309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    bos.write(b, 0, readLength);
45409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    position += readLength;
45509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
456ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) {
45709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Receive file position = " + position + " readLength "
45809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + readLength + " bytes took "
45909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + (System.currentTimeMillis() - timestamp) + " ms");
46009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
46109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
46209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    ContentValues updateValues = new ContentValues();
46309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    updateValues.put(BluetoothShare.CURRENT_BYTES, position);
46409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mContext.getContentResolver().update(contentUri, updateValues, null, null);
46509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
46609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (IOException e1) {
46709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.e(TAG, "Error when receiving file");
46809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = BluetoothShare.STATUS_OBEX_DATA_ERROR;
46909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                error = true;
47009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
47109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
47209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
47309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mInterrupted) {
474ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly            if (D) Log.d(TAG, "receiving file interrupted by user.");
47509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            status = BluetoothShare.STATUS_CANCELED;
47609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else {
47709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (position == fileInfo.mLength) {
478ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.d(TAG, "Receiving file completed for " + fileInfo.mFileName);
47909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                status = BluetoothShare.STATUS_SUCCESS;
48009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
481ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (D) Log.d(TAG, "Reading file failed at " + position + " of " + fileInfo.mLength);
48209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (status == -1) {
48309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    status = BluetoothShare.STATUS_UNKNOWN_ERROR;
48409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
48509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
48609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
48709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
48809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (bos != null) {
48909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
49009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                bos.close();
49109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (IOException e) {
49209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.e(TAG, "Error when closing stream after send");
49309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
49409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
49509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return status;
49609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
49709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
49809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppReceiveFileInfo processShareInfo() {
499ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "processShareInfo() " + mInfo.mId);
50009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BluetoothOppReceiveFileInfo fileInfo = BluetoothOppReceiveFileInfo.generateFileInfo(
50109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mContext, mInfo.mId);
502ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) {
50309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Generate BluetoothOppReceiveFileInfo:");
50409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "filename  :" + fileInfo.mFileName);
50509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "length    :" + fileInfo.mLength);
50609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "status    :" + fileInfo.mStatus);
50709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
50809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return fileInfo;
50909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
51009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
51109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
51209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public int onConnect(HeaderSet request, HeaderSet reply) {
51309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
514ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "onConnect");
515ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (V) Constants.logHeader(request);
51609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
51709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mTimestamp = System.currentTimeMillis();
51809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return ResponseCodes.OBEX_HTTP_OK;
51909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
52009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
52109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
52209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void onDisconnect(HeaderSet req, HeaderSet resp) {
52309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
524ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly        if (D) Log.d(TAG, "onDisconnect");
52509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        resp.responseCode = ResponseCodes.OBEX_HTTP_OK;
52652236de777c23788df8147de15912a57e8bc36ddTao Liejun
52709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /* onDisconnect could happen even before start() where mCallback is set */
52809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mCallback != null) {
52909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Message msg = Message.obtain(mCallback);
53009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.what = BluetoothOppObexSession.MSG_SESSION_COMPLETE;
53109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.obj = mInfo;
53209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            msg.sendToTarget();
53309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
53409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
53509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
53609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
53709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void onClose() {
53832e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        if (V) Log.v(TAG, "release WakeLock");
53932e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        if (mWakeLock.isHeld()) {
54032e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun            mWakeLock.release();
54132e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        }
54232e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        if (mPartialWakeLock.isHeld()) {
54332e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun            mPartialWakeLock.release();
54432e47df203390052c1ef771d78b22fc4aa5f9e72Tao Liejun        }
54509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
54609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly}
547