/* * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the Motorola, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.android.bluetooth.opp; import android.app.Activity; import android.app.AlertDialog; import android.bluetooth.BluetoothAdapter; import android.content.DialogInterface; import android.content.Intent; import android.database.Cursor; import android.database.StaleDataException; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import com.android.bluetooth.R; /** * View showing the user's finished bluetooth opp transfers that the user does * not confirm. Including outbound and inbound transfers, both successful and * failed. * */ public class BluetoothOppTransferHistory extends Activity implements View.OnCreateContextMenuListener, OnItemClickListener { private static final String TAG = "BluetoothOppTransferHistory"; private static final boolean V = Constants.VERBOSE; private ListView mListView; private Cursor mTransferCursor; private BluetoothOppTransferAdapter mTransferAdapter; private int mIdColumnId; private int mContextMenuPosition; private boolean mShowAllIncoming; private boolean mContextMenu = false; /** Class to handle Notification Manager updates */ private BluetoothOppNotification mNotifier; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.bluetooth_transfers_page); mListView = (ListView) findViewById(R.id.list); mListView.setEmptyView(findViewById(R.id.empty)); mShowAllIncoming = getIntent().getBooleanExtra(Constants.EXTRA_SHOW_ALL_FILES, false); String direction; int dir = getIntent().getIntExtra("direction", 0); if (dir == BluetoothShare.DIRECTION_OUTBOUND) { setTitle(getText(R.string.outbound_history_title)); direction = "(" + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_OUTBOUND + ")"; } else { if (mShowAllIncoming) { setTitle(getText(R.string.btopp_live_folder)); } else { setTitle(getText(R.string.inbound_history_title)); } direction = "(" + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_INBOUND + ")"; } String selection = BluetoothShare.STATUS + " >= '200' AND " + direction; if (!mShowAllIncoming) { selection = selection + " AND (" + BluetoothShare.VISIBILITY + " IS NULL OR " + BluetoothShare.VISIBILITY + " == '" + BluetoothShare.VISIBILITY_VISIBLE + "')"; } final String sortOrder = BluetoothShare.TIMESTAMP + " DESC"; mTransferCursor = getContentResolver().query(BluetoothShare.CONTENT_URI, new String[]{ "_id", BluetoothShare.FILENAME_HINT, BluetoothShare.STATUS, BluetoothShare.TOTAL_BYTES, BluetoothShare._DATA, BluetoothShare.TIMESTAMP, BluetoothShare.VISIBILITY, BluetoothShare.DESTINATION, BluetoothShare.DIRECTION }, selection, null, sortOrder); // only attach everything to the listbox if we can access // the transfer database. Otherwise, just show it empty if (mTransferCursor != null) { mIdColumnId = mTransferCursor.getColumnIndexOrThrow(BluetoothShare._ID); // Create a list "controller" for the data mTransferAdapter = new BluetoothOppTransferAdapter(this, R.layout.bluetooth_transfer_item, mTransferCursor); mListView.setAdapter(mTransferAdapter); mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET); mListView.setOnCreateContextMenuListener(this); mListView.setOnItemClickListener(this); } mNotifier = new BluetoothOppNotification(this); mContextMenu = false; } @Override public boolean onCreateOptionsMenu(Menu menu) { if (mTransferCursor != null && !mShowAllIncoming) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.transferhistory, menu); } return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (!mShowAllIncoming) { menu.findItem(R.id.transfer_menu_clear_all).setEnabled(isTransferComplete()); } return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.transfer_menu_clear_all: promptClearList(); return true; } return false; } @Override public boolean onContextItemSelected(MenuItem item) { if (mTransferCursor.getCount() == 0) { Log.i(TAG, "History is already cleared, not clearing again"); return true; } mTransferCursor.moveToPosition(mContextMenuPosition); switch (item.getItemId()) { case R.id.transfer_menu_open: openCompleteTransfer(); updateNotificationWhenBtDisabled(); return true; case R.id.transfer_menu_clear: int sessionId = mTransferCursor.getInt(mIdColumnId); Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + sessionId); BluetoothOppUtility.updateVisibilityToHidden(this, contentUri); updateNotificationWhenBtDisabled(); return true; } return false; } @Override protected void onDestroy() { if (mTransferCursor != null) { mTransferCursor.close(); } super.onDestroy(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (mTransferCursor != null) { mContextMenu = true; AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; mTransferCursor.moveToPosition(info.position); mContextMenuPosition = info.position; String fileName = mTransferCursor.getString( mTransferCursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT)); if (fileName == null) { fileName = this.getString(R.string.unknown_file); } menu.setHeaderTitle(fileName); MenuInflater inflater = getMenuInflater(); if (mShowAllIncoming) { inflater.inflate(R.menu.receivedfilescontextfinished, menu); } else { inflater.inflate(R.menu.transferhistorycontextfinished, menu); } } } /** * Prompt the user if they would like to clear the transfer history */ private void promptClearList() { new AlertDialog.Builder(this).setTitle(R.string.transfer_clear_dlg_title) .setMessage(R.string.transfer_clear_dlg_msg) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { clearAllDownloads(); } }) .setNegativeButton(android.R.string.cancel, null) .show(); } /** * Returns true if the device has finished transfers, including error and success. */ private boolean isTransferComplete() { try { if (mTransferCursor.moveToFirst()) { while (!mTransferCursor.isAfterLast()) { int statusColumnId = mTransferCursor .getColumnIndexOrThrow(BluetoothShare.STATUS); int status = mTransferCursor.getInt(statusColumnId); if (BluetoothShare.isStatusCompleted(status)) { return true; } mTransferCursor.moveToNext(); } } } catch (StaleDataException e) { } return false; } /** * Clear all finished transfers, error and success transfer items. */ private void clearAllDownloads() { if (mTransferCursor.moveToFirst()) { while (!mTransferCursor.isAfterLast()) { int sessionId = mTransferCursor.getInt(mIdColumnId); Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + sessionId); BluetoothOppUtility.updateVisibilityToHidden(this, contentUri); mTransferCursor.moveToNext(); } updateNotificationWhenBtDisabled(); } } /* * (non-Javadoc) * @see * android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget * .AdapterView, android.view.View, int, long) */ @Override public void onItemClick(AdapterView parent, View view, int position, long id) { // Open the selected item if (V) { Log.v(TAG, "onItemClick: ContextMenu = " + mContextMenu); } if (!mContextMenu) { mTransferCursor.moveToPosition(position); openCompleteTransfer(); updateNotificationWhenBtDisabled(); } mContextMenu = false; } /** * Open the selected finished transfer. mDownloadCursor must be moved to * appropriate position before calling this function */ private void openCompleteTransfer() { int sessionId = mTransferCursor.getInt(mIdColumnId); Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + sessionId); BluetoothOppTransferInfo transInfo = BluetoothOppUtility.queryRecord(this, contentUri); if (transInfo == null) { Log.e(TAG, "Error: Can not get data from db"); return; } if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND && BluetoothShare.isStatusSuccess(transInfo.mStatus)) { // if received file successfully, open this file BluetoothOppUtility.updateVisibilityToHidden(this, contentUri); BluetoothOppUtility.openReceivedFile(this, transInfo.mFileName, transInfo.mFileType, transInfo.mTimeStamp, contentUri); } else { Intent in = new Intent(this, BluetoothOppTransferActivity.class); in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); in.setDataAndNormalize(contentUri); this.startActivity(in); } } /** * When Bluetooth is disabled, notification can not be updated by * ContentObserver in OppService, so need update manually. */ private void updateNotificationWhenBtDisabled() { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (!adapter.isEnabled()) { if (V) { Log.v(TAG, "Bluetooth is not enabled, update notification manually."); } mNotifier.updateNotification(); } } }