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