BluetoothOppService.java revision df7415da0e510ab8e4b73831a5ade38306982fe1
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 com.google.android.collect.Lists;
3609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport javax.obex.ObexTransport;
3709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.app.Service;
3909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.bluetooth.BluetoothDevice;
4009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.bluetooth.BluetoothError;
4109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.bluetooth.BluetoothIntent;
4209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.BroadcastReceiver;
4309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.ContentUris;
4409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.ContentValues;
4509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Context;
4609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Intent;
4709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.IntentFilter;
4809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.database.CharArrayBuffer;
4909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.database.ContentObserver;
5009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.database.Cursor;
5109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.media.MediaScannerConnection;
5209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.media.MediaScannerConnection.MediaScannerConnectionClient;
5309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.net.Uri;
5409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Handler;
5509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.IBinder;
5609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Message;
5709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.PowerManager;
5809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.util.Log;
5909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.os.Process;
6009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
6109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.FileNotFoundException;
6209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.IOException;
6309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.io.InputStream;
6409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.util.ArrayList;
6509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
6609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/**
676769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun * Performs the background Bluetooth OPP transfer. It also starts thread to
686769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun * accept incoming OPP connection.
6909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */
7009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypublic class BluetoothOppService extends Service {
7209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean userAccepted = false;
7409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private class BluetoothShareContentObserver extends ContentObserver {
7609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public BluetoothShareContentObserver() {
7809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            super(new Handler());
7909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
8009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
8109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        @Override
8209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void onChange(boolean selfChange) {
8309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (Constants.LOGVV) {
8409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(Constants.TAG, "Service ContentObserver received notification");
8509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
8609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            updateFromProvider();
8709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
8809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
8909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private static final String TAG = "BtOpp Service";
9109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /** Observer to get notified when the content observer's data changes */
9309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothShareContentObserver mObserver;
9409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /** Class to handle Notification Manager updates */
9609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppNotification mNotifier;
9709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
9809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean mPendingUpdate;
9909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private UpdateThread mUpdateThread;
10109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private ArrayList<BluetoothOppShareInfo> mShares;
10309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private ArrayList<BluetoothOppBatch> mBatchs;
10509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppTransfer mTransfer;
10709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
10809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppTransfer mServerTransfer;
10909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int mBatchId;
11109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
11309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Array used when extracting strings from content provider
11409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
11509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private CharArrayBuffer mOldChars;
11609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
11809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Array used when extracting strings from content provider
11909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
12009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private CharArrayBuffer mNewChars;
12109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothDevice mBluetooth;
12309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private PowerManager mPowerManager;
12509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppRfcommListener mSocketListener;
12709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean mListenStarted = false;
12909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
13009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /*
13109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * TODO No support for queue incoming from multiple devices.
13209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Make an array list of server session to support receiving queue from
13309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * multiple devices
13409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
13509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private BluetoothOppObexServerSession mServerSession;
13609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
13709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
13809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public IBinder onBind(Intent arg0) {
13909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        throw new UnsupportedOperationException("Cannot bind to Bluetooth OPP Service");
14009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
14109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
14209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
14309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void onCreate() {
14409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        super.onCreate();
14509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
14609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Service onCreate");
14709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
14809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mBluetooth = (BluetoothDevice)getSystemService(Context.BLUETOOTH_SERVICE);
14909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mPowerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
15009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mSocketListener = new BluetoothOppRfcommListener();
15109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mShares = Lists.newArrayList();
15209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mBatchs = Lists.newArrayList();
15309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mObserver = new BluetoothShareContentObserver();
15409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true, mObserver);
15509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mBatchId = 1;
15609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mNotifier = new BluetoothOppNotification(this);
15709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mNotifier.mNotificationMgr.cancelAll();
15809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mNotifier.updateNotification();
15909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
16009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        trimDatabase();
16109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
16209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        IntentFilter filter = new IntentFilter(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
16309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
16409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        registerReceiver(mBluetoothIntentReceiver, filter);
16509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
1666769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        synchronized (BluetoothOppService.this) {
16709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mBluetooth == null) {
16809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.w(TAG, "Local BT device is not enabled");
16909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
17009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                startListenerDelayed();
17109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
17209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
17309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
17409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BluetoothOppPreference.getInstance(this).dump();
17509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        updateFromProvider();
17609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
17709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
17809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
17909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void onStart(Intent intent, int startId) {
18009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        super.onStart(intent, startId);
18109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
18209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Service onStart");
18309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
18409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
18509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mBluetooth == null) {
18609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.w(TAG, "Local BT device is not enabled");
18709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else {
18809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            startListenerDelayed();
18909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
19009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        updateFromProvider();
19109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
19209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
19309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
19409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void startListenerDelayed() {
19509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!mListenStarted) {
19609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mBluetooth.isEnabled()) {
19709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
19809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Starting RfcommListener in 9 seconds");
19909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
20009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mHandler.sendMessageDelayed(mHandler.obtainMessage(START_LISTENER), 9000);
20109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mListenStarted = true;
20209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
20309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
20409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
20509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
20609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private static final int START_LISTENER = 1;
20709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
20809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private static final int MEDIA_SCANNED = 2;
20909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
21009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private static final int MEDIA_SCANNED_FAILED = 3;
21109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
21209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private Handler mHandler = new Handler() {
21309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        @Override
21409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void handleMessage(Message msg) {
21509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            switch (msg.what) {
21609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                case START_LISTENER:
21709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (mBluetooth.isEnabled()) {
21809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        startSocketListener();
21909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
22009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    break;
22109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                case MEDIA_SCANNED:
22209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Update mInfo.id " + msg.arg1 + " for data uri= "
22309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            + msg.obj.toString());
22409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    ContentValues updateValues = new ContentValues();
22509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + msg.arg1);
22609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    updateValues.put(Constants.MEDIA_SCANNED, Constants.MEDIA_SCANNED_SCANNED_OK);
22709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    updateValues.put(BluetoothShare.URI, msg.obj.toString()); // update
22809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    updateValues.put(BluetoothShare.MIMETYPE, getContentResolver().getType(
22909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Uri.parse(msg.obj.toString())));
23009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    getContentResolver().update(contentUri, updateValues, null, null);
23109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
23209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    break;
23309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                case MEDIA_SCANNED_FAILED:
23409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Update mInfo.id " + msg.arg1 + " for MEDIA_SCANNED_FAILED");
23509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    ContentValues updateValues1 = new ContentValues();
23609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Uri contentUri1 = Uri.parse(BluetoothShare.CONTENT_URI + "/" + msg.arg1);
23709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    updateValues1.put(Constants.MEDIA_SCANNED,
23809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Constants.MEDIA_SCANNED_SCANNED_FAILED);
23909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    getContentResolver().update(contentUri1, updateValues1, null, null);
24009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
24109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
24209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
24309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    };
24409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
24509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void startSocketListener() {
24609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
24709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
24809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "start RfcommListener");
24909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
25009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mSocketListener.start(mIncomingConnectionHandler);
25109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
25209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "RfcommListener started");
25309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
25409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
25509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    @Override
25709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void onDestroy() {
25809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
25909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Service onDestroy");
26009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
26109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        super.onDestroy();
26209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        getContentResolver().unregisterContentObserver(mObserver);
26309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        unregisterReceiver(mBluetoothIntentReceiver);
26409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mSocketListener.stop();
26509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
26609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
26709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private final Handler mIncomingConnectionHandler = new Handler() {
26809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void handleMessage(Message msg) {
26909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (Constants.LOGV) {
27009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(TAG, "Get incoming connection");
27109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
27209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            ObexTransport transport = (ObexTransport)msg.obj;
27309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /*
27409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * TODO need to identify in which case we can create a
27509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             * serverSession, and when we will reject connection
27609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly             */
27709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            createServerSession(transport);
27809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
27909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    };
28009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
28109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /* suppose we auto accept an incoming OPUSH connection */
28209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void createServerSession(ObexTransport transport) {
28309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mServerSession = new BluetoothOppObexServerSession(this, transport);
28409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mServerSession.preStart();
28509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGV) {
28609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Get ServerSession " + mServerSession.toString()
28709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    + " for incoming connection" + transport.toString());
28809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
28909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
29009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
29109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void handleRemoteDisconnected(String address) {
29209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
29309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Handle remote device disconnected " + address);
29409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
29509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int batchId = -1;
29609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int i;
29709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mTransfer != null) {
29809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            batchId = mTransfer.getBatchId();
29909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            i = findBatchWithId(batchId);
30009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (i != -1 && mBatchs.get(i).mStatus == Constants.BATCH_STATUS_RUNNING
30109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    && mBatchs.get(i).mDestination.equals(address)) {
30209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
30309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Find mTransfer is running for remote device " + address);
30409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
30509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mTransfer.stop();
30609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
30709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
30809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        } else if (mServerTransfer != null) {
30909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            batchId = mServerTransfer.getBatchId();
31009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            i = findBatchWithId(batchId);
31109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (i != -1 && mBatchs.get(i).mStatus == Constants.BATCH_STATUS_RUNNING
31209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    && mBatchs.get(i).mDestination.equals(address)) {
31309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
31409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Find mServerTransfer is running for remote device " + address);
31509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
31609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
31709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
31809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
31909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
32009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private final BroadcastReceiver mBluetoothIntentReceiver = new BroadcastReceiver() {
32109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        @Override
32209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void onReceive(Context context, Intent intent) {
32309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            String action = intent.getAction();
32409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
32509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
32609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (action.equals(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION)) {
32709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
32809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Receiver REMOTE_DEVICE_DISCONNECTED_ACTION from " + address);
32909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
33009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                handleRemoteDisconnected(address);
33109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
33209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
33309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
33409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                switch (intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE, BluetoothError.ERROR)) {
33509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    case BluetoothDevice.BLUETOOTH_STATE_ON:
33609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (Constants.LOGVV) {
33709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Log.v(TAG,
33809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    "Receiver BLUETOOTH_STATE_CHANGED_ACTION, BLUETOOTH_STATE_ON");
33909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
34009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        startSocketListener();
34109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        break;
34209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    case BluetoothDevice.BLUETOOTH_STATE_TURNING_OFF:
34309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (Constants.LOGVV) {
34409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Log.v(TAG, "Receiver DISABLED_ACTION ");
34509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
34609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mSocketListener.stop();
34709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mListenStarted = false;
3486769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun                        synchronized (BluetoothOppService.this) {
34909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            if (mUpdateThread == null) {
35009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                stopSelf();
35109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            }
35209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
35309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        break;
35409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
35509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
35609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
35709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    };
35809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
35909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void updateFromProvider() {
3606769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        synchronized (BluetoothOppService.this) {
36109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mPendingUpdate = true;
36209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mUpdateThread == null) {
36309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mUpdateThread = new UpdateThread();
36409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mUpdateThread.start();
36509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
36609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
36709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
36809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
36909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private class UpdateThread extends Thread {
37009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public UpdateThread() {
37109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            super("Bluetooth Share Service");
37209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
37309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
37409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        @Override
37509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void run() {
37609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
37709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
37809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            boolean keepUpdateThread = false;
37909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            for (;;) {
3806769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun                synchronized (BluetoothOppService.this) {
38109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (mUpdateThread != this) {
38209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        throw new IllegalStateException(
38309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                "multiple UpdateThreads in BluetoothOppService");
38409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
38509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
38609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "pendingUpdate is " + mPendingUpdate + " keepUpdateThread is "
38709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + keepUpdateThread + " sListenStarted is " + mListenStarted);
38809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
38909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (!mPendingUpdate) {
39009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mUpdateThread = null;
39109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (!keepUpdateThread && !mListenStarted) {
39209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            stopSelf();
39309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            break;
39409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
39509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        return;
39609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
39709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mPendingUpdate = false;
39809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
39909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Cursor cursor = getContentResolver().query(BluetoothShare.CONTENT_URI, null, null,
40009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        null, BluetoothShare._ID);
40109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
40209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (cursor == null) {
40309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    return;
40409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
40509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
40609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.moveToFirst();
40709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
40809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                int arrayPos = 0;
40909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
41009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                keepUpdateThread = false;
41109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                boolean isAfterLast = cursor.isAfterLast();
41209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
41309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                int idColumn = cursor.getColumnIndexOrThrow(BluetoothShare._ID);
41409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /*
41509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * Walk the cursor and the local array to keep them in sync. The
41609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * key to the algorithm is that the ids are unique and sorted
41709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * both in the cursor and in the array, so that they can be
41809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * processed in order in both sources at the same time: at each
41909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * step, both sources point to the lowest id that hasn't been
42009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * processed from that source, and the algorithm processes the
42109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * lowest id from those two possibilities. At each step: -If the
42209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * array contains an entry that's not in the cursor, remove the
42309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * entry, move to next entry in the array. -If the array
42409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * contains an entry that's in the cursor, nothing to do, move
42509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * to next cursor row and next array entry. -If the cursor
42609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * contains an entry that's not in the array, insert a new entry
42709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 * in the array, move to next cursor row and next array entry.
42809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                 */
42909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                while (!isAfterLast || arrayPos < mShares.size()) {
43009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (isAfterLast) {
43109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        // We're beyond the end of the cursor but there's still
43209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        // some
43309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        // stuff in the local array, which can only be junk
43409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (Constants.LOGVV) {
4356769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun                            int arrayId = mShares.get(arrayPos).mId;
43609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Log.v(TAG, "Array update: trimming " + arrayId + " @ " + arrayPos);
43709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
43809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
43909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (shouldScanFile(arrayPos)) {
44009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            scanFile(null, arrayPos);
44109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
44209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        deleteShare(arrayPos); // this advances in the array
44309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else {
44409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        int id = cursor.getInt(idColumn);
44509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
44609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (arrayPos == mShares.size()) {
44709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            insertShare(cursor, arrayPos);
44809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            if (Constants.LOGVV) {
44909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                Log.v(TAG, "Array update: inserting " + id + " @ " + arrayPos);
45009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            }
45109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            if (shouldScanFile(arrayPos) && (!scanFile(cursor, arrayPos))) {
45209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                keepUpdateThread = true;
45309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            }
45409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            if (visibleNotification(arrayPos)) {
45509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                keepUpdateThread = true;
45609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            }
45709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            if (needAction(arrayPos)) {
45809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                keepUpdateThread = true;
45909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            }
46009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
46109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            ++arrayPos;
46209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            cursor.moveToNext();
46309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            isAfterLast = cursor.isAfterLast();
46409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        } else {
46509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            int arrayId = mShares.get(arrayPos).mId;
46609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
46709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            if (arrayId < id) {
46809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (Constants.LOGVV) {
46909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    Log.v(TAG, "Array update: removing " + arrayId + " @ "
47009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                            + arrayPos);
47109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
47209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (shouldScanFile(arrayPos)) {
47309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    scanFile(null, arrayPos);
47409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
47509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                deleteShare(arrayPos);
47609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            } else if (arrayId == id) {
47709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                // This cursor row already exists in the stored
47809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                // array
47909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                updateShare(cursor, arrayPos, userAccepted);
48009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (shouldScanFile(arrayPos) && (!scanFile(cursor, arrayPos))) {
48109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    keepUpdateThread = true;
48209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
48309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (visibleNotification(arrayPos)) {
48409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    keepUpdateThread = true;
48509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
48609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (needAction(arrayPos)) {
48709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    keepUpdateThread = true;
48809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
48909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
49009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                ++arrayPos;
49109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                cursor.moveToNext();
49209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                isAfterLast = cursor.isAfterLast();
49309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            } else {
49409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                // This cursor entry didn't exist in the stored
49509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                // array
49609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (Constants.LOGVV) {
49709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    Log.v(TAG, "Array update: appending " + id + " @ " + arrayPos);
49809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
49909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                insertShare(cursor, arrayPos);
50009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
50109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (shouldScanFile(arrayPos) && (!scanFile(cursor, arrayPos))) {
50209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    keepUpdateThread = true;
50309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
50409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (visibleNotification(arrayPos)) {
50509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    keepUpdateThread = true;
50609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
50709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                if (needAction(arrayPos)) {
50809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                    keepUpdateThread = true;
50909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                }
51009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                ++arrayPos;
51109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                cursor.moveToNext();
51209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                isAfterLast = cursor.isAfterLast();
51309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            }
51409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
51509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
51609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
51709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
51809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mNotifier.updateNotification();
51909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
52009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.close();
52109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
52209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
52309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
52409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
52509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
52609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void insertShare(Cursor cursor, int arrayPos) {
52709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        BluetoothOppShareInfo info = new BluetoothOppShareInfo(
52809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID)),
52909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.URI)),
53009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)),
53109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare._DATA)),
53209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.MIMETYPE)),
53309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION)),
53409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getString(cursor.getColumnIndexOrThrow(BluetoothShare.DESTINATION)),
53509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.VISIBILITY)),
53609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION)),
53709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.STATUS)),
53809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES)),
53909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES)),
54009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP)),
54109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) != Constants.MEDIA_SCANNED_NOT_SCANNED);
54209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
54309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
54409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Service adding new entry");
54509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "ID      : " + info.mId);
54609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            // Log.v(TAG, "URI     : " + ((info.mUri != null) ? "yes" : "no"));
54709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "URI     : " + info.mUri);
54809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "HINT    : " + info.mHint);
54909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "FILENAME: " + info.mFilename);
55009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "MIMETYPE: " + info.mMimetype);
55109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "DIRECTION: " + info.mDirection);
55209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "DESTINAT: " + info.mDestination);
55309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "VISIBILI: " + info.mVisibility);
55409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "CONFIRM : " + info.mConfirm);
55509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "STATUS  : " + info.mStatus);
55609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "TOTAL   : " + info.mTotalBytes);
55709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "CURRENT : " + info.mCurrentBytes);
55809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "TIMESTAMP : " + info.mTimestamp);
55909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "SCANNED : " + info.mMediaScanned);
56009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
56109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
56209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mShares.add(arrayPos, info);
56309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
56409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /* Mark the info as failed if it's in invalid status */
56509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (info.isObsolete()) {
56609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_UNKNOWN_ERROR);
56709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
56809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
56909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * Add info into a batch. The logic is
57009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 1) Only add valid and readyToStart info
57109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 2) If there is no batch, create a batch and insert this transfer into batch,
57209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * then run the batch
57309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 3) If there is existing batch and timestamp match, insert transfer into batch
57409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 4) If there is existing batch and timestamp does not match, create a new batch and
57509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * put in queue
57609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
57709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
57809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (info.isReadyToStart()) {
57909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
58009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                /* check if the file exists */
58109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                try {
58209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    InputStream i = getContentResolver().openInputStream(Uri.parse(info.mUri));
58309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    i.close();
58409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } catch (FileNotFoundException e) {
58509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.e(TAG, "Can't open file for OUTBOUND info " + info.mId);
58609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
58709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    return;
58809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } catch (IOException ex) {
58909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.e(TAG, "IO error when close file for OUTBOUND info " + info.mId);
59009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    return;
59109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
59209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
59309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mBatchs.size() == 0) {
59409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                BluetoothOppBatch newBatch = new BluetoothOppBatch(this, info);
59509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                newBatch.mId = mBatchId;
59609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mBatchId++;
59709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mBatchs.add(newBatch);
59809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
59909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
60009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Service create new Batch " + newBatch.mId
60109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + " for OUTBOUND info " + info.mId);
60209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
60309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch);
60409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else if (info.mDirection == BluetoothShare.DIRECTION_INBOUND) {
60509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
60609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Service create new Batch " + newBatch.mId
60709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + " for INBOUND info " + info.mId);
60809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
60909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mServerTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch,
61009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            mServerSession);
61109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
61209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
61309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (info.mDirection == BluetoothShare.DIRECTION_OUTBOUND && mTransfer != null) {
61409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
61509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Service start transfer new Batch " + newBatch.mId
61609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + " for info " + info.mId);
61709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
61809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mTransfer.start();
61909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else if (info.mDirection == BluetoothShare.DIRECTION_INBOUND
62009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        && mServerTransfer != null) {
62109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    /*
62209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                     * TODO investigate here later?
62309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                     */
62409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
62509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Service start server transfer new Batch " + newBatch.mId
62609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + " for info " + info.mId);
62709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
62809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mServerTransfer.start();
62909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
63009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
63109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
63209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                int i = findBatchWithTimeStamp(info.mTimestamp);
63309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (i != -1) {
63409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
63509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Service add info " + info.mId + " to existing batch "
63609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + mBatchs.get(i).mId);
63709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
63809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mBatchs.get(i).addShare(info);
63909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
64009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    BluetoothOppBatch newBatch = new BluetoothOppBatch(this, info);
64109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    newBatch.mId = mBatchId;
64209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mBatchId++;
64309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    mBatchs.add(newBatch);
64409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (Constants.LOGVV) {
64509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.v(TAG, "Service add new Batch " + newBatch.mId + " for info "
64609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + info.mId);
64709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
64809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
64909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
65009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
65109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
65209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
65309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void updateShare(Cursor cursor, int arrayPos, boolean userAccepted) {
6546769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        BluetoothOppShareInfo info = mShares.get(arrayPos);
65509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int statusColumn = cursor.getColumnIndexOrThrow(BluetoothShare.STATUS);
65609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
65709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mId = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID));
65809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mUri = stringFromCursor(info.mUri, cursor, BluetoothShare.URI);
65909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mHint = stringFromCursor(info.mHint, cursor, BluetoothShare.FILENAME_HINT);
66009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mFilename = stringFromCursor(info.mFilename, cursor, BluetoothShare._DATA);
66109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mMimetype = stringFromCursor(info.mMimetype, cursor, BluetoothShare.MIMETYPE);
66209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mDirection = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION));
66309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mDestination = stringFromCursor(info.mDestination, cursor, BluetoothShare.DESTINATION);
66409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int newVisibility = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.VISIBILITY));
66509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
66609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        boolean confirmed = false;
66709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int newConfirm = cursor.getInt(cursor
66809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                .getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION));
66909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
67009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (info.mVisibility == BluetoothShare.VISIBILITY_VISIBLE
67109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                && newVisibility != BluetoothShare.VISIBILITY_VISIBLE
67209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                && (BluetoothShare.isStatusCompleted(info.mStatus) || newConfirm == BluetoothShare.USER_CONFIRMATION_PENDING)) {
67309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mNotifier.mNotificationMgr.cancel(info.mId);
67409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
67509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
67609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mVisibility = newVisibility;
67709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
67809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (info.mConfirm == BluetoothShare.USER_CONFIRMATION_PENDING
67909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                && newConfirm != BluetoothShare.USER_CONFIRMATION_PENDING) {
68009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            confirmed = true;
68109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
68209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mConfirm = cursor.getInt(cursor
68309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                .getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION));
68409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int newStatus = cursor.getInt(statusColumn);
68509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
68609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (!BluetoothShare.isStatusCompleted(info.mStatus)
68709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                && BluetoothShare.isStatusCompleted(newStatus)) {
68809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mNotifier.mNotificationMgr.cancel(info.mId);
68909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
69009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
69109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mStatus = newStatus;
69209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mTotalBytes = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES));
69309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mCurrentBytes = cursor.getInt(cursor
69409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                .getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES));
69509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mTimestamp = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP));
69609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        info.mMediaScanned = (cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) != Constants.MEDIA_SCANNED_NOT_SCANNED);
69709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
69809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (confirmed) {
69909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (Constants.LOGVV) {
70009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(TAG, "Service handle info " + info.mId + " confirmed");
70109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
70209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            /* Inbounds transfer get user confirmation, so we start it */
703df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun            int i = findBatchWithTimeStamp(info.mTimestamp);
704df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun            BluetoothOppBatch batch = mBatchs.get(i);
705df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun            if (batch.mId == mServerTransfer.getBatchId()) {
706df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun                mServerTransfer.setConfirmed();
707df7415da0e510ab8e4b73831a5ade38306982fe1Tao Liejun            } //TODO need to think about else
70809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
70909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int i = findBatchWithTimeStamp(info.mTimestamp);
71009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (i != -1) {
71109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            BluetoothOppBatch batch = mBatchs.get(i);
71209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (batch.mStatus == Constants.BATCH_STATUS_FINISHED
71309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    || batch.mStatus == Constants.BATCH_STATUS_FAILED) {
71409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
71509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Batch " + batch.mId + " is finished");
71609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
71709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (batch.mDirection == BluetoothShare.DIRECTION_OUTBOUND) {
71809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (mTransfer == null) {
71909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.e(TAG, "Unexpected error! mTransfer is null");
72009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else if (batch.mId == mTransfer.getBatchId()) {
72109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mTransfer.stop();
72209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else {
72309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.e(TAG, "Unexpected error! batch id " + batch.mId
72409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + " doesn't match mTransfer id " + mTransfer.getBatchId());
72509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
72609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
72709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (mServerTransfer == null) {
72809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.e(TAG, "Unexpected error! mServerTransfer is null");
72909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else if (batch.mId == mServerTransfer.getBatchId()) {
73009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mServerTransfer.stop();
73109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    } else {
73209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        Log.e(TAG, "Unexpected error! batch id " + batch.mId
73309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + " doesn't match mServerTransfer id "
73409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                + mServerTransfer.getBatchId());
73509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
73609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
73709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                removeBatch(batch);
73809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
73909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
74009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
74109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
74209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
74309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Removes the local copy of the info about a share.
74409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
74509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void deleteShare(int arrayPos) {
7466769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        BluetoothOppShareInfo info = mShares.get(arrayPos);
74709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
74809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        /*
74909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * Delete arrayPos from a batch. The logic is
75009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 1) Search existing batch for the info
75109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 2) cancel the batch
75209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         * 3) If the batch become empty delete the batch
75309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly         */
75409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int i = findBatchWithTimeStamp(info.mTimestamp);
75509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (i != -1) {
75609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            BluetoothOppBatch batch = mBatchs.get(i);
75709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (batch.hasShare(info)) {
75809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
75909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Service cancel batch for share " + info.mId);
76009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
76109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                batch.cancelBatch();
76209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
76309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (batch.isEmpty()) {
76409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
76509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "Service remove batch  " + batch.mId);
76609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
76709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                removeBatch(batch);
76809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
76909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
77009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mShares.remove(arrayPos);
77109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
77209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
77309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private String stringFromCursor(String old, Cursor cursor, String column) {
77409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int index = cursor.getColumnIndexOrThrow(column);
77509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (old == null) {
77609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return cursor.getString(index);
77709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
77809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mNewChars == null) {
77909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mNewChars = new CharArrayBuffer(128);
78009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
78109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        cursor.copyStringToBuffer(index, mNewChars);
78209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int length = mNewChars.sizeCopied;
78309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (length != old.length()) {
78409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return cursor.getString(index);
78509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
78609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mOldChars == null || mOldChars.sizeCopied < length) {
78709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mOldChars = new CharArrayBuffer(length);
78809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
78909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        char[] oldArray = mOldChars.data;
79009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        char[] newArray = mNewChars.data;
79109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        old.getChars(0, length, oldArray, 0);
79209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        for (int i = length - 1; i >= 0; --i) {
79309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (oldArray[i] != newArray[i]) {
79409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                return new String(newArray, 0, length);
79509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
79609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
79709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return old;
79809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
79909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
80009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int findBatchWithTimeStamp(long timestamp) {
80109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        for (int i = mBatchs.size() - 1; i >= 0; i--) {
80209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mBatchs.get(i).mTimestamp == timestamp) {
80309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                return i;
80409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
80509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
80609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return -1;
80709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
80809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
80909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private int findBatchWithId(int id) {
81009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
81109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Service search batch for id " + id + " from " + mBatchs.size());
81209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
81309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        for (int i = mBatchs.size() - 1; i >= 0; i--) {
81409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mBatchs.get(i).mId == id) {
81509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                return i;
81609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
81709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
81809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return -1;
81909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
82009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
82109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void removeBatch(BluetoothOppBatch batch) {
82209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (Constants.LOGVV) {
82309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.v(TAG, "Remove batch " + batch.mId);
82409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
82509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mBatchs.remove(batch);
82609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (mBatchs.size() > 0) {
82709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            for (int i = 0; i < mBatchs.size(); i++) {
82809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                // we have a running batch
82909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (mBatchs.get(i).mStatus == Constants.BATCH_STATUS_RUNNING) {
83009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    return;
83109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
83209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    /*
83309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                     * TODO Pending batch for inbound transfer is not considered
83409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                     * here
83509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                     */
83609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    // we have a pending batch
83709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    if (batch.mDirection == mBatchs.get(i).mDirection) {
83809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        if (Constants.LOGVV) {
83909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            Log.v(TAG, "Start pending batch " + mBatchs.get(i).mId);
84009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        }
84109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mTransfer = new BluetoothOppTransfer(this, mPowerManager, mBatchs.get(i));
84209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        mTransfer.start();
84309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        return;
84409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    }
84509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
84609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
84709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
84809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
84909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
85009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean needAction(int arrayPos) {
8516769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        BluetoothOppShareInfo info = mShares.get(arrayPos);
85209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (BluetoothShare.isStatusCompleted(info.mStatus)) {
85309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return false;
85409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
85509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return true;
85609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
85709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
85809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean visibleNotification(int arrayPos) {
8596769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        BluetoothOppShareInfo info = mShares.get(arrayPos);
86009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return info.hasCompletionNotification();
86109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
86209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
86309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean scanFile(Cursor cursor, int arrayPos) {
8646769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        BluetoothOppShareInfo info = mShares.get(arrayPos);
8656769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        synchronized (BluetoothOppService.this) {
86609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (Constants.LOGV) {
86709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(TAG, "Scanning file " + info.mFilename);
86809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
86909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            new MediaScannerNotifier(this, info, mHandler);
87009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return true;
87109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
87209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
87309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
87409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private boolean shouldScanFile(int arrayPos) {
8756769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun        BluetoothOppShareInfo info = mShares.get(arrayPos);
87609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        return !info.mMediaScanned && info.mDirection == BluetoothShare.DIRECTION_INBOUND
87709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                && BluetoothShare.isStatusSuccess(info.mStatus);
87809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
87909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
88009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
88109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void trimDatabase() {
88209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Cursor cursor = getContentResolver().query(BluetoothShare.CONTENT_URI, new String[] {
88309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            BluetoothShare._ID
88409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }, BluetoothShare.STATUS + " >= '200'", null, BluetoothShare._ID);
88509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (cursor == null) {
88609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            // This isn't good - if we can't do basic queries in our database,
88709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            // nothing's gonna work
88809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Log.e(TAG, "null cursor in trimDatabase");
88909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return;
89009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
89109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (cursor.moveToFirst()) {
89209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int numDelete = cursor.getCount() - Constants.MAX_RECORDS_IN_DATABASE;
89309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int columnId = cursor.getColumnIndexOrThrow(BluetoothShare._ID);
89409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            while (numDelete > 0) {
89509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                getContentResolver().delete(
89609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                        ContentUris.withAppendedId(BluetoothShare.CONTENT_URI, cursor
89709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                                .getLong(columnId)), null, null);
89809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (!cursor.moveToNext()) {
89909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    break;
90009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
90109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                numDelete--;
90209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
90309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
90409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        cursor.close();
90509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
90609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
90709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private static class MediaScannerNotifier implements MediaScannerConnectionClient {
90809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
90909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        private MediaScannerConnection mConnection;
91009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
91109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        private BluetoothOppShareInfo mInfo;
91209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
91309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        private Context mContext;
91409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
91509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        private Handler mCallback;
91609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
91709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public MediaScannerNotifier(Context context, BluetoothOppShareInfo info, Handler handler) {
91809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mContext = context;
91909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mInfo = info;
92009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mCallback = handler;
92109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mConnection = new MediaScannerConnection(mContext, this);
92209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (Constants.LOGVV) {
92309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(TAG, "Connecting to MediaScannerConnection ");
92409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
92509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mConnection.connect();
92609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
92709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
92809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void onMediaScannerConnected() {
92909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (Constants.LOGVV) {
93009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(TAG, "MediaScannerConnection onMediaScannerConnected");
93109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
93209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mConnection.scanFile(mInfo.mFilename, mInfo.mMimetype);
93309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
93409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
93509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        public void onScanCompleted(String path, Uri uri) {
93609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            try {
93709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
93809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "MediaScannerConnection onScanCompleted");
93909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "MediaScannerConnection path is " + path);
94009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "MediaScannerConnection Uri is " + uri);
94109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
94209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (uri != null) {
94309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Message msg = Message.obtain();
94409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.setTarget(mCallback);
94509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.what = MEDIA_SCANNED;
94609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.arg1 = mInfo.mId;
94709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.obj = uri;
94809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.sendToTarget();
94909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
95009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Message msg = Message.obtain();
95109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.setTarget(mCallback);
95209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.what = MEDIA_SCANNED_FAILED;
95309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.arg1 = mInfo.mId;
95409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    msg.sendToTarget();
95509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
95609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } catch (Exception ex) {
95709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                Log.v(TAG, "!!!MediaScannerConnection exception: " + ex);
95809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } finally {
95909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (Constants.LOGVV) {
96009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    Log.v(TAG, "MediaScannerConnection disconnect");
96109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
96209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mConnection.disconnect();
96309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
96409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
96509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
96609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly}
967