• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.app.Activity;
38 import android.app.AlertDialog;
39 import android.bluetooth.BluetoothAdapter;
40 import android.content.DialogInterface;
41 import android.content.Intent;
42 import android.database.Cursor;
43 import android.net.Uri;
44 import android.os.Bundle;
45 import android.util.Log;
46 import android.view.ContextMenu;
47 import android.view.ContextMenu.ContextMenuInfo;
48 import android.view.Menu;
49 import android.view.MenuInflater;
50 import android.view.MenuItem;
51 import android.view.View;
52 import android.widget.AdapterView;
53 import android.widget.AdapterView.OnItemClickListener;
54 import android.widget.ListView;
55 
56 /**
57  * View showing the user's finished bluetooth opp transfers that the user does
58  * not confirm. Including outbound and inbound transfers, both successful and
59  * failed. *
60  */
61 public class BluetoothOppTransferHistory extends Activity implements
62         View.OnCreateContextMenuListener, OnItemClickListener {
63     private static final String TAG = "BluetoothOppTransferHistory";
64 
65     private static final boolean V = Constants.VERBOSE;
66 
67     private ListView mListView;
68 
69     private Cursor mTransferCursor;
70 
71     private BluetoothOppTransferAdapter mTransferAdapter;
72 
73     private int mIdColumnId;
74 
75     private int mContextMenuPosition;
76 
77     private boolean mShowAllIncoming;
78 
79     private boolean mContextMenu = false;
80 
81     /** Class to handle Notification Manager updates */
82     private BluetoothOppNotification mNotifier;
83 
84     @Override
onCreate(Bundle icicle)85     public void onCreate(Bundle icicle) {
86         super.onCreate(icicle);
87         setContentView(R.layout.bluetooth_transfers_page);
88         mListView = (ListView)findViewById(R.id.list);
89         mListView.setEmptyView(findViewById(R.id.empty));
90 
91         mShowAllIncoming = getIntent().getBooleanExtra(
92                 Constants.EXTRA_SHOW_ALL_FILES, false);
93 
94         String direction;
95         int dir = getIntent().getIntExtra("direction", 0);
96         if (dir == BluetoothShare.DIRECTION_OUTBOUND) {
97             setTitle(getText(R.string.outbound_history_title));
98             direction = "(" + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_OUTBOUND
99                     + ")";
100         } else {
101             if (mShowAllIncoming) {
102                 setTitle(getText(R.string.btopp_live_folder));
103             } else {
104                 setTitle(getText(R.string.inbound_history_title));
105             }
106             direction = "(" + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_INBOUND
107                     + ")";
108         }
109 
110         String selection = BluetoothShare.STATUS + " >= '200' AND " + direction;
111 
112         if (!mShowAllIncoming) {
113             selection = selection + " AND ("
114                     + BluetoothShare.VISIBILITY + " IS NULL OR "
115                     + BluetoothShare.VISIBILITY + " == '"
116                     + BluetoothShare.VISIBILITY_VISIBLE + "')";
117         }
118 
119         final String sortOrder = BluetoothShare.TIMESTAMP + " DESC";
120 
121         mTransferCursor = managedQuery(BluetoothShare.CONTENT_URI, new String[] {
122                 "_id", BluetoothShare.FILENAME_HINT, BluetoothShare.STATUS,
123                 BluetoothShare.TOTAL_BYTES, BluetoothShare._DATA, BluetoothShare.TIMESTAMP,
124                 BluetoothShare.VISIBILITY, BluetoothShare.DESTINATION, BluetoothShare.DIRECTION
125         }, selection, sortOrder);
126 
127         // only attach everything to the listbox if we can access
128         // the transfer database. Otherwise, just show it empty
129         if (mTransferCursor != null) {
130             mIdColumnId = mTransferCursor.getColumnIndexOrThrow(BluetoothShare._ID);
131             // Create a list "controller" for the data
132             mTransferAdapter = new BluetoothOppTransferAdapter(this,
133                     R.layout.bluetooth_transfer_item, mTransferCursor);
134             mListView.setAdapter(mTransferAdapter);
135             mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
136             mListView.setOnCreateContextMenuListener(this);
137             mListView.setOnItemClickListener(this);
138         }
139 
140         mNotifier = new BluetoothOppNotification(this);
141         mContextMenu = false;
142     }
143 
144     @Override
onCreateOptionsMenu(Menu menu)145     public boolean onCreateOptionsMenu(Menu menu) {
146         if (mTransferCursor != null && !mShowAllIncoming) {
147             MenuInflater inflater = getMenuInflater();
148             inflater.inflate(R.menu.transferhistory, menu);
149         }
150         return true;
151     }
152 
153     @Override
onPrepareOptionsMenu(Menu menu)154     public boolean onPrepareOptionsMenu(Menu menu) {
155         if (!mShowAllIncoming) {
156             boolean showClear = getClearableCount() > 0;
157             menu.findItem(R.id.transfer_menu_clear_all).setEnabled(showClear);
158         }
159         return super.onPrepareOptionsMenu(menu);
160     }
161 
162     @Override
onOptionsItemSelected(MenuItem item)163     public boolean onOptionsItemSelected(MenuItem item) {
164         switch (item.getItemId()) {
165             case R.id.transfer_menu_clear_all:
166                 promptClearList();
167                 return true;
168         }
169         return false;
170     }
171 
172     @Override
onContextItemSelected(MenuItem item)173     public boolean onContextItemSelected(MenuItem item) {
174         if (mTransferCursor.getCount() == 0) {
175             Log.i(TAG, "History is already cleared, not clearing again");
176             return true;
177         }
178         mTransferCursor.moveToPosition(mContextMenuPosition);
179         switch (item.getItemId()) {
180             case R.id.transfer_menu_open:
181                 openCompleteTransfer();
182                 updateNotificationWhenBtDisabled();
183                 return true;
184 
185             case R.id.transfer_menu_clear:
186                 int sessionId = mTransferCursor.getInt(mIdColumnId);
187                 Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + sessionId);
188                 BluetoothOppUtility.updateVisibilityToHidden(this, contentUri);
189                 updateNotificationWhenBtDisabled();
190                 return true;
191         }
192         return false;
193     }
194 
195     @Override
onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)196     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
197         if (mTransferCursor != null) {
198             mContextMenu = true;
199             AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
200             mTransferCursor.moveToPosition(info.position);
201             mContextMenuPosition = info.position;
202 
203             String fileName = mTransferCursor.getString(mTransferCursor
204                     .getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT));
205             if (fileName == null) {
206                 fileName = this.getString(R.string.unknown_file);
207             }
208             menu.setHeaderTitle(fileName);
209 
210             MenuInflater inflater = getMenuInflater();
211             if (mShowAllIncoming) {
212                 inflater.inflate(R.menu.receivedfilescontextfinished, menu);
213             } else {
214                 inflater.inflate(R.menu.transferhistorycontextfinished, menu);
215             }
216         }
217     }
218 
219     /**
220      * Prompt the user if they would like to clear the transfer history
221      */
promptClearList()222     private void promptClearList() {
223         new AlertDialog.Builder(this).setTitle(R.string.transfer_clear_dlg_title).setMessage(
224                 R.string.transfer_clear_dlg_msg).setPositiveButton(android.R.string.ok,
225                 new DialogInterface.OnClickListener() {
226                     public void onClick(DialogInterface dialog, int whichButton) {
227                         clearAllDownloads();
228                     }
229                 }).setNegativeButton(android.R.string.cancel, null).show();
230     }
231 
232     /**
233      * Get the number of finished transfers, including error and success.
234      */
getClearableCount()235     private int getClearableCount() {
236         int count = 0;
237         if (mTransferCursor.moveToFirst()) {
238             while (!mTransferCursor.isAfterLast()) {
239                 int statusColumnId = mTransferCursor.getColumnIndexOrThrow(BluetoothShare.STATUS);
240                 int status = mTransferCursor.getInt(statusColumnId);
241                 if (BluetoothShare.isStatusCompleted(status)) {
242                     count++;
243                 }
244                 mTransferCursor.moveToNext();
245             }
246         }
247         return count;
248     }
249 
250     /**
251      * Clear all finished transfers, error and success transfer items.
252      */
clearAllDownloads()253     private void clearAllDownloads() {
254         if (mTransferCursor.moveToFirst()) {
255             while (!mTransferCursor.isAfterLast()) {
256                 int sessionId = mTransferCursor.getInt(mIdColumnId);
257                 Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + sessionId);
258                 BluetoothOppUtility.updateVisibilityToHidden(this, contentUri);
259 
260                 mTransferCursor.moveToNext();
261             }
262             updateNotificationWhenBtDisabled();
263         }
264     }
265 
266     /*
267      * (non-Javadoc)
268      * @see
269      * android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget
270      * .AdapterView, android.view.View, int, long)
271      */
onItemClick(AdapterView<?> parent, View view, int position, long id)272     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
273         // Open the selected item
274         if (V) Log.v(TAG, "onItemClick: ContextMenu = " + mContextMenu);
275         if (!mContextMenu) {
276             mTransferCursor.moveToPosition(position);
277             openCompleteTransfer();
278             updateNotificationWhenBtDisabled();
279         }
280         mContextMenu = false;
281     }
282 
283     /**
284      * Open the selected finished transfer. mDownloadCursor must be moved to
285      * appropriate position before calling this function
286      */
openCompleteTransfer()287     private void openCompleteTransfer() {
288         int sessionId = mTransferCursor.getInt(mIdColumnId);
289         Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + sessionId);
290         BluetoothOppTransferInfo transInfo = BluetoothOppUtility.queryRecord(this, contentUri);
291         if (transInfo == null) {
292             Log.e(TAG, "Error: Can not get data from db");
293             return;
294         }
295         if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND
296                 && BluetoothShare.isStatusSuccess(transInfo.mStatus)) {
297             // if received file successfully, open this file
298             BluetoothOppUtility.updateVisibilityToHidden(this, contentUri);
299             BluetoothOppUtility.openReceivedFile(this, transInfo.mFileName, transInfo.mFileType,
300                     transInfo.mTimeStamp, contentUri);
301         } else {
302             Intent in = new Intent(this, BluetoothOppTransferActivity.class);
303             in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
304             in.setDataAndNormalize(contentUri);
305             this.startActivity(in);
306         }
307     }
308 
309     /**
310      * When Bluetooth is disabled, notification can not be updated by
311      * ContentObserver in OppService, so need update manually.
312      */
updateNotificationWhenBtDisabled()313     private void updateNotificationWhenBtDisabled() {
314         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
315         if (!adapter.isEnabled()) {
316             if (V) Log.v(TAG, "Bluetooth is not enabled, update notification manually.");
317             mNotifier.updateNotification();
318         }
319     }
320 }
321