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