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