OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / packages / apps / Bluetooth / src / com / android / bluetooth / opp / BluetoothOppManager.java
1 /*
2  * Copyright (c) 2008-2009, Motorola, Inc.
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * - Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * - Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * - Neither the name of the Motorola, Inc. nor the names of its contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 package com.android.bluetooth.opp;
34
35 import com.android.bluetooth.R;
36
37 import android.bluetooth.BluetoothAdapter;
38 import android.bluetooth.BluetoothDevice;
39 import android.content.ContentResolver;
40 import android.content.ContentValues;
41 import android.content.Context;
42 import android.content.Intent;
43 import android.content.SharedPreferences;
44 import android.net.Uri;
45 import android.os.Process;
46 import android.text.TextUtils;
47 import android.util.Log;
48
49 import java.util.ArrayList;
50
51 /**
52  * This class provides a simplified interface on top of other Bluetooth service
53  * layer components; Also it handles some Opp application level variables. It's
54  * a singleton got from BluetoothOppManager.getInstance(context);
55  */
56 public class BluetoothOppManager {
57     private static final String TAG = "BluetoothOppManager";
58     private static final boolean D = Constants.DEBUG;
59     private static final boolean V = Constants.VERBOSE;
60
61     private static BluetoothOppManager INSTANCE;
62
63     /** Used when obtaining a reference to the singleton instance. */
64     private static Object INSTANCE_LOCK = new Object();
65
66     private boolean mInitialized;
67
68     private Context mContext;
69
70     private BluetoothAdapter mAdapter;
71
72     private String mMimeTypeOfSendingFile;
73
74     private String mUriOfSendingFile;
75
76     private String mMimeTypeOfSendingFiles;
77
78     private ArrayList<Uri> mUrisOfSendingFiles;
79
80     private static final String OPP_PREFERENCE_FILE = "OPPMGR";
81
82     private static final String SENDING_FLAG = "SENDINGFLAG";
83
84     private static final String MIME_TYPE = "MIMETYPE";
85
86     private static final String FILE_URI = "FILE_URI";
87
88     private static final String MIME_TYPE_MULTIPLE = "MIMETYPE_MULTIPLE";
89
90     private static final String FILE_URIS = "FILE_URIS";
91
92     private static final String MULTIPLE_FLAG = "MULTIPLE_FLAG";
93
94     private static final String ARRAYLIST_ITEM_SEPERATOR = ";";
95
96     private static final int ALLOWED_INSERT_SHARE_THREAD_NUMBER = 3;
97
98     // used to judge if need continue sending process after received a
99     // ENABLED_ACTION
100     public boolean mSendingFlag;
101
102     public boolean mMultipleFlag;
103
104     private int mfileNumInBatch;
105
106     private int mInsertShareThreadNum = 0;
107
108     /**
109      * Get singleton instance.
110      */
111     public static BluetoothOppManager getInstance(Context context) {
112         synchronized (INSTANCE_LOCK) {
113             if (INSTANCE == null) {
114                 INSTANCE = new BluetoothOppManager();
115             }
116             INSTANCE.init(context);
117
118             return INSTANCE;
119         }
120     }
121
122     /**
123      * init
124      */
125     private boolean init(Context context) {
126         if (mInitialized)
127             return true;
128         mInitialized = true;
129
130         mContext = context;
131
132         mAdapter = BluetoothAdapter.getDefaultAdapter();
133         if (mAdapter == null) {
134             if (V) Log.v(TAG, "BLUETOOTH_SERVICE is not started! ");
135         }
136
137         // Restore data from preference
138         restoreApplicationData();
139
140         return true;
141     }
142
143     /**
144      * Restore data from preference
145      */
146     private void restoreApplicationData() {
147         SharedPreferences settings = mContext.getSharedPreferences(OPP_PREFERENCE_FILE, 0);
148
149         // All member vars are not initialized till now
150         mSendingFlag = settings.getBoolean(SENDING_FLAG, false);
151         mMimeTypeOfSendingFile = settings.getString(MIME_TYPE, null);
152         mUriOfSendingFile = settings.getString(FILE_URI, null);
153         mMimeTypeOfSendingFiles = settings.getString(MIME_TYPE_MULTIPLE, null);
154         mMultipleFlag = settings.getBoolean(MULTIPLE_FLAG, false);
155
156         if (V) Log.v(TAG, "restoreApplicationData! " + mSendingFlag + mMultipleFlag
157                     + mMimeTypeOfSendingFile + mUriOfSendingFile);
158
159         String strUris = settings.getString(FILE_URIS, null);
160         mUrisOfSendingFiles = new ArrayList<Uri>();
161         if (strUris != null) {
162             String[] splitUri = strUris.split(ARRAYLIST_ITEM_SEPERATOR);
163             for (int i = 0; i < splitUri.length; i++) {
164                 mUrisOfSendingFiles.add(Uri.parse(splitUri[i]));
165                 if (V) Log.v(TAG, "Uri in batch:  " + Uri.parse(splitUri[i]));
166             }
167         }
168
169         mContext.getSharedPreferences(OPP_PREFERENCE_FILE, 0).edit().clear().apply();
170     }
171
172     /**
173      * Save application data to preference, need restore these data when service restart
174      */
175     private void storeApplicationData() {
176         SharedPreferences.Editor editor = mContext.getSharedPreferences(OPP_PREFERENCE_FILE, 0)
177                 .edit();
178         editor.putBoolean(SENDING_FLAG, mSendingFlag);
179         editor.putBoolean(MULTIPLE_FLAG, mMultipleFlag);
180         if (mMultipleFlag) {
181             editor.putString(MIME_TYPE_MULTIPLE, mMimeTypeOfSendingFiles);
182             StringBuilder sb = new StringBuilder();
183             for (int i = 0, count = mUrisOfSendingFiles.size(); i < count; i++) {
184                 Uri uriContent = mUrisOfSendingFiles.get(i);
185                 sb.append(uriContent);
186                 sb.append(ARRAYLIST_ITEM_SEPERATOR);
187             }
188             String strUris = sb.toString();
189             editor.putString(FILE_URIS, strUris);
190
191             editor.remove(MIME_TYPE);
192             editor.remove(FILE_URI);
193         } else {
194             editor.putString(MIME_TYPE, mMimeTypeOfSendingFile);
195             editor.putString(FILE_URI, mUriOfSendingFile);
196
197             editor.remove(MIME_TYPE_MULTIPLE);
198             editor.remove(FILE_URIS);
199         }
200         editor.apply();
201         if (V) Log.v(TAG, "Application data stored to SharedPreference! ");
202     }
203
204     public void saveSendingFileInfo(String mimeType, String uri) {
205         synchronized (BluetoothOppManager.this) {
206             mMultipleFlag = false;
207             mMimeTypeOfSendingFile = mimeType;
208             mUriOfSendingFile = uri;
209             storeApplicationData();
210         }
211     }
212
213     public void saveSendingFileInfo(String mimeType, ArrayList<Uri> uris) {
214         synchronized (BluetoothOppManager.this) {
215             mMultipleFlag = true;
216             mMimeTypeOfSendingFiles = mimeType;
217             mUrisOfSendingFiles = uris;
218             storeApplicationData();
219         }
220     }
221
222     /**
223      * Get the current status of Bluetooth hardware.
224      * @return true if Bluetooth enabled, false otherwise.
225      */
226     public boolean isEnabled() {
227         if (mAdapter != null) {
228             return mAdapter.isEnabled();
229         } else {
230             if (V) Log.v(TAG, "BLUETOOTH_SERVICE is not available! ");
231             return false;
232         }
233     }
234
235     /**
236      * Enable Bluetooth hardware.
237      */
238     public void enableBluetooth() {
239         if (mAdapter != null) {
240             mAdapter.enable();
241         }
242     }
243
244     /**
245      * Disable Bluetooth hardware.
246      */
247     public void disableBluetooth() {
248         if (mAdapter != null) {
249             mAdapter.disable();
250         }
251     }
252
253     /**
254      * Get device name per bluetooth address.
255      */
256     public String getDeviceName(BluetoothDevice device) {
257         String deviceName;
258
259         deviceName = BluetoothOppPreference.getInstance(mContext).getName(device);
260
261         if (deviceName == null && mAdapter != null) {
262             deviceName = device.getName();
263         }
264
265         if (deviceName == null) {
266             deviceName = mContext.getString(R.string.unknown_device);
267         }
268
269         return deviceName;
270     }
271
272     public int getBatchSize() {
273         synchronized (BluetoothOppManager.this) {
274             return mfileNumInBatch;
275         }
276     }
277
278     /**
279      * Fork a thread to insert share info to db.
280      */
281     public void startTransfer(BluetoothDevice device) {
282         if (V) Log.v(TAG, "Active InsertShareThread number is : " + mInsertShareThreadNum);
283         InsertShareInfoThread insertThread;
284         synchronized (BluetoothOppManager.this) {
285             if (mInsertShareThreadNum > ALLOWED_INSERT_SHARE_THREAD_NUMBER) {
286                 Log.e(TAG, "Too many shares user triggered concurrently!");
287
288                 // Notice user
289                 Intent in = new Intent(mContext, BluetoothOppBtErrorActivity.class);
290                 in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
291                 in.putExtra("title", mContext.getString(R.string.enabling_progress_title));
292                 in.putExtra("content", mContext.getString(R.string.ErrorTooManyRequests));
293                 mContext.startActivity(in);
294
295                 return;
296             }
297             insertThread = new InsertShareInfoThread(device, mMultipleFlag, mMimeTypeOfSendingFile,
298                     mUriOfSendingFile, mMimeTypeOfSendingFiles, mUrisOfSendingFiles);
299             if (mMultipleFlag) {
300                 mfileNumInBatch = mUrisOfSendingFiles.size();
301             }
302         }
303
304         insertThread.start();
305     }
306
307     /**
308      * Thread to insert share info to db. In multiple files (say 100 files)
309      * share case, the inserting share info to db operation would be a time
310      * consuming operation, so need a thread to handle it. This thread allows
311      * multiple instances to support below case: User select multiple files to
312      * share to one device (say device 1), and then right away share to second
313      * device (device 2), we need insert all these share info to db.
314      */
315     private class InsertShareInfoThread extends Thread {
316         private final BluetoothDevice mRemoteDevice;
317
318         private final String mTypeOfSingleFile;
319
320         private final String mUri;
321
322         private final String mTypeOfMultipleFiles;
323
324         private final ArrayList<Uri> mUris;
325
326         private final boolean mIsMultiple;
327
328         public InsertShareInfoThread(BluetoothDevice device, boolean multiple,
329                 String typeOfSingleFile, String uri, String typeOfMultipleFiles, ArrayList<Uri> uris) {
330             super("Insert ShareInfo Thread");
331             this.mRemoteDevice = device;
332             this.mIsMultiple = multiple;
333             this.mTypeOfSingleFile = typeOfSingleFile;
334             this.mUri = uri;
335             this.mTypeOfMultipleFiles = typeOfMultipleFiles;
336             this.mUris = uris;
337
338             synchronized (BluetoothOppManager.this) {
339                 mInsertShareThreadNum++;
340             }
341
342             if (V) Log.v(TAG, "Thread id is: " + this.getId());
343         }
344
345         @Override
346         public void run() {
347             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
348             if (mRemoteDevice == null) {
349                 Log.e(TAG, "Target bt device is null!");
350                 return;
351             }
352             if (mIsMultiple) {
353                 insertMultipleShare();
354             } else {
355                 insertSingleShare();
356             }
357             synchronized (BluetoothOppManager.this) {
358                 mInsertShareThreadNum--;
359             }
360         }
361
362         /**
363          * Insert multiple sending sessions to db, only used by Opp application.
364          */
365         private void insertMultipleShare() {
366             int count = mUris.size();
367             Long ts = System.currentTimeMillis();
368             for (int i = 0; i < count; i++) {
369                 Uri fileUri = mUris.get(i);
370                 ContentResolver contentResolver = mContext.getContentResolver();
371                 String contentType = contentResolver.getType(fileUri);
372                 if (V) Log.v(TAG, "Got mimetype: " + contentType + "  Got uri: " + fileUri);
373                 if (TextUtils.isEmpty(contentType)) {
374                     contentType = mTypeOfMultipleFiles;
375                 }
376
377                 ContentValues values = new ContentValues();
378                 values.put(BluetoothShare.URI, fileUri.toString());
379                 values.put(BluetoothShare.MIMETYPE, contentType);
380                 values.put(BluetoothShare.DESTINATION, mRemoteDevice.getAddress());
381                 values.put(BluetoothShare.TIMESTAMP, ts);
382
383                 final Uri contentUri = mContext.getContentResolver().insert(
384                         BluetoothShare.CONTENT_URI, values);
385                 if (V) Log.v(TAG, "Insert contentUri: " + contentUri + "  to device: "
386                             + getDeviceName(mRemoteDevice));
387             }
388         }
389
390          /**
391          * Insert single sending session to db, only used by Opp application.
392          */
393         private void insertSingleShare() {
394             ContentValues values = new ContentValues();
395             values.put(BluetoothShare.URI, mUri);
396             values.put(BluetoothShare.MIMETYPE, mTypeOfSingleFile);
397             values.put(BluetoothShare.DESTINATION, mRemoteDevice.getAddress());
398
399             final Uri contentUri = mContext.getContentResolver().insert(BluetoothShare.CONTENT_URI,
400                     values);
401             if (V) Log.v(TAG, "Insert contentUri: " + contentUri + "  to device: "
402                                 + getDeviceName(mRemoteDevice));
403         }
404     }
405
406 }