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