BluetoothOppTransferActivity.java revision 1f0fc26568c1babf0c66d2c75812b72e894eb0de
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.bluetooth.BluetoothAdapter;
38import android.bluetooth.BluetoothDevice;
39import android.content.Context;
40import android.content.DialogInterface;
41import android.content.Intent;
42import android.net.Uri;
43import android.os.Bundle;
44import android.os.Handler;
45import android.util.Log;
46import android.view.View;
47import android.widget.TextView;
48import android.widget.Toast;
49import android.database.ContentObserver;
50import android.widget.ProgressBar;
51
52import com.android.internal.app.AlertActivity;
53import com.android.internal.app.AlertController;
54import android.app.NotificationManager;
55import android.text.format.Formatter;
56
57/**
58 * Handle all transfer related dialogs: -Ongoing transfer -Receiving one file
59 * dialog -Sending one file dialog -sending multiple files dialog -Complete
60 * transfer -receive -receive success, will trigger corresponding handler
61 * -receive fail dialog -send -send success dialog -send fail dialog -Other
62 * dialogs - - DIALOG_RECEIVE_ONGOING will transition to
63 * DIALOG_RECEIVE_COMPLETE_SUCCESS or DIALOG_RECEIVE_COMPLETE_FAIL
64 * DIALOG_SEND_ONGOING will transition to DIALOG_SEND_COMPLETE_SUCCESS or
65 * DIALOG_SEND_COMPLETE_FAIL
66 */
67public class BluetoothOppTransferActivity extends AlertActivity implements
68        DialogInterface.OnClickListener {
69    private static final String TAG = "BluetoothOppTransferActivity";
70    private static final boolean D = Constants.DEBUG;
71    private static final boolean V = Constants.VERBOSE;
72
73    private Uri mUri;
74
75    // ongoing transfer-0 complete transfer-1
76    boolean mIsComplete;
77
78    private BluetoothOppTransferInfo mTransInfo;
79
80    private ProgressBar mProgressTransfer;
81
82    private TextView mPercentView;
83
84    private AlertController.AlertParams mPara;
85
86    private View mView = null;
87
88    private TextView mLine1View, mLine2View, mLine3View, mLine5View;
89
90    private int mWhichDialog;
91
92    private BluetoothAdapter mAdapter;
93
94    // Dialogs definition:
95    // Receive progress dialog
96    public static final int DIALOG_RECEIVE_ONGOING = 0;
97
98    // Receive complete and success dialog
99    public static final int DIALOG_RECEIVE_COMPLETE_SUCCESS = 1;
100
101    // Receive complete and fail dialog: will display some fail reason
102    public static final int DIALOG_RECEIVE_COMPLETE_FAIL = 2;
103
104    // Send progress dialog
105    public static final int DIALOG_SEND_ONGOING = 3;
106
107    // Send complete and success dialog
108    public static final int DIALOG_SEND_COMPLETE_SUCCESS = 4;
109
110    // Send complete and fail dialog: will let user retry
111    public static final int DIALOG_SEND_COMPLETE_FAIL = 5;
112
113    /** Observer to get notified when the content observer's data changes */
114    private BluetoothTransferContentObserver mObserver;
115
116    private class BluetoothTransferContentObserver extends ContentObserver {
117        public BluetoothTransferContentObserver() {
118            super(new Handler());
119        }
120
121        @Override
122        public void onChange(boolean selfChange) {
123            if (V) Log.v(TAG, "received db changes.");
124            updateProgressbar();
125        }
126    }
127
128    @Override
129    protected void onCreate(Bundle savedInstanceState) {
130        super.onCreate(savedInstanceState);
131        Intent intent = getIntent();
132        mUri = intent.getData();
133
134        mTransInfo = new BluetoothOppTransferInfo();
135        mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
136        if (mTransInfo == null) {
137            if (V) Log.e(TAG, "Error: Can not get data from db");
138            finish();
139            return;
140        }
141
142        mIsComplete = BluetoothShare.isStatusCompleted(mTransInfo.mStatus);
143
144        displayWhichDialog();
145
146        // update progress bar for ongoing transfer
147        if (!mIsComplete) {
148            mObserver = new BluetoothTransferContentObserver();
149            getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true,
150                    mObserver);
151        }
152
153        if (mWhichDialog != DIALOG_SEND_ONGOING && mWhichDialog != DIALOG_RECEIVE_ONGOING) {
154            // set this record to INVISIBLE
155            BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
156        }
157
158        mAdapter = BluetoothAdapter.getDefaultAdapter();
159
160        // Set up the "dialog"
161        setUpDialog();
162    }
163
164    @Override
165    protected void onDestroy() {
166        if (D) Log.d(TAG, "onDestroy()");
167
168        if (mObserver != null) {
169            getContentResolver().unregisterContentObserver(mObserver);
170        }
171        super.onDestroy();
172    }
173
174    private void displayWhichDialog() {
175        int direction = mTransInfo.mDirection;
176        boolean isSuccess = BluetoothShare.isStatusSuccess(mTransInfo.mStatus);
177        boolean isComplete = BluetoothShare.isStatusCompleted(mTransInfo.mStatus);
178
179        if (direction == BluetoothShare.DIRECTION_INBOUND) {
180            if (isComplete == true) {
181                if (isSuccess == true) {
182                    // should not go here
183                    mWhichDialog = DIALOG_RECEIVE_COMPLETE_SUCCESS;
184                } else if (isSuccess == false) {
185                    mWhichDialog = DIALOG_RECEIVE_COMPLETE_FAIL;
186                }
187            } else if (isComplete == false) {
188                mWhichDialog = DIALOG_RECEIVE_ONGOING;
189            }
190        } else if (direction == BluetoothShare.DIRECTION_OUTBOUND) {
191            if (isComplete == true) {
192                if (isSuccess == true) {
193                    mWhichDialog = DIALOG_SEND_COMPLETE_SUCCESS;
194
195                } else if (isSuccess == false) {
196                    mWhichDialog = DIALOG_SEND_COMPLETE_FAIL;
197                }
198            } else if (isComplete == false) {
199                mWhichDialog = DIALOG_SEND_ONGOING;
200            }
201        }
202
203        if (V) Log.v(TAG, " WhichDialog/dir/isComplete/failOrSuccess" + mWhichDialog + direction
204                    + isComplete + isSuccess);
205    }
206
207    private void setUpDialog() {
208        // final AlertController.AlertParams p = mAlertParams;
209        mPara = mAlertParams;
210        mPara.mIconId = android.R.drawable.ic_dialog_info;
211        mPara.mTitle = getString(R.string.download_title);
212
213        if ((mWhichDialog == DIALOG_RECEIVE_ONGOING) || (mWhichDialog == DIALOG_SEND_ONGOING)) {
214            mPara.mPositiveButtonText = getString(R.string.download_ok);
215            mPara.mPositiveButtonListener = this;
216            mPara.mNegativeButtonText = getString(R.string.download_cancel);
217            mPara.mNegativeButtonListener = this;
218        } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
219            mPara.mPositiveButtonText = getString(R.string.download_succ_ok);
220            mPara.mPositiveButtonListener = this;
221        } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
222            mPara.mIconId = android.R.drawable.ic_dialog_alert;
223            mPara.mPositiveButtonText = getString(R.string.download_fail_ok);
224            mPara.mPositiveButtonListener = this;
225        } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
226            mPara.mPositiveButtonText = getString(R.string.upload_succ_ok);
227            mPara.mPositiveButtonListener = this;
228        } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
229            mPara.mIconId = android.R.drawable.ic_dialog_alert;
230            mPara.mPositiveButtonText = getString(R.string.upload_fail_ok);
231            mPara.mPositiveButtonListener = this;
232            mPara.mNegativeButtonText = getString(R.string.upload_fail_cancel);
233            mPara.mNegativeButtonListener = this;
234        }
235        mPara.mView = createView();
236        setupAlert();
237    }
238
239    private View createView() {
240
241        mView = getLayoutInflater().inflate(R.layout.file_transfer, null);
242
243        mProgressTransfer = (ProgressBar)mView.findViewById(R.id.progress_transfer);
244        mPercentView = (TextView)mView.findViewById(R.id.progress_percent);
245
246        customizeViewContent();
247
248        updateProgressbar();
249
250        return mView;
251    }
252
253    /**
254     * customize the content of view
255     */
256    private void customizeViewContent() {
257        String tmp;
258
259        if (mWhichDialog == DIALOG_RECEIVE_ONGOING
260                || mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
261            mLine1View = (TextView)mView.findViewById(R.id.line1_view);
262            tmp = getString(R.string.download_line1, mTransInfo.mDeviceName);
263            mLine1View.setText(tmp);
264            mLine2View = (TextView)mView.findViewById(R.id.line2_view);
265            tmp = getString(R.string.download_line2, mTransInfo.mFileName);
266            mLine2View.setText(tmp);
267            mLine3View = (TextView)mView.findViewById(R.id.line3_view);
268            tmp = getString(R.string.download_line3, Formatter.formatFileSize(this,
269                    mTransInfo.mTotalBytes));
270            mLine3View.setText(tmp);
271            mLine5View = (TextView)mView.findViewById(R.id.line5_view);
272            if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
273                tmp = getString(R.string.download_line5);
274            } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
275                tmp = getString(R.string.download_succ_line5);
276            }
277            mLine5View.setText(tmp);
278        } else if (mWhichDialog == DIALOG_SEND_ONGOING
279                || mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
280            mLine1View = (TextView)mView.findViewById(R.id.line1_view);
281            tmp = getString(R.string.upload_line1, mTransInfo.mDeviceName);
282            mLine1View.setText(tmp);
283            mLine2View = (TextView)mView.findViewById(R.id.line2_view);
284            tmp = getString(R.string.download_line2, mTransInfo.mFileName);
285            mLine2View.setText(tmp);
286            mLine3View = (TextView)mView.findViewById(R.id.line3_view);
287            tmp = getString(R.string.upload_line3, mTransInfo.mFileType, Formatter.formatFileSize(
288                    this, mTransInfo.mTotalBytes));
289            mLine3View.setText(tmp);
290            mLine5View = (TextView)mView.findViewById(R.id.line5_view);
291            if (mWhichDialog == DIALOG_SEND_ONGOING) {
292                tmp = getString(R.string.upload_line5);
293            } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
294                tmp = getString(R.string.upload_succ_line5);
295            }
296            mLine5View.setText(tmp);
297        } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
298            if (mTransInfo.mStatus == BluetoothShare.STATUS_ERROR_SDCARD_FULL) {
299                mLine1View = (TextView)mView.findViewById(R.id.line1_view);
300                tmp = getString(R.string.bt_sm_2_1, mTransInfo.mDeviceName);
301                mLine1View.setText(tmp);
302                mLine2View = (TextView)mView.findViewById(R.id.line2_view);
303                tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
304                mLine2View.setText(tmp);
305                mLine3View = (TextView)mView.findViewById(R.id.line3_view);
306                tmp = getString(R.string.bt_sm_2_2, Formatter.formatFileSize(this,
307                        mTransInfo.mTotalBytes));
308                mLine3View.setText(tmp);
309            } else {
310                mLine1View = (TextView)mView.findViewById(R.id.line1_view);
311                tmp = getString(R.string.download_fail_line1);
312                mLine1View.setText(tmp);
313                mLine2View = (TextView)mView.findViewById(R.id.line2_view);
314                tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
315                mLine2View.setText(tmp);
316                mLine3View = (TextView)mView.findViewById(R.id.line3_view);
317                tmp = getString(R.string.download_fail_line3, BluetoothOppUtility
318                        .getStatusDescription(this, mTransInfo.mStatus));
319                mLine3View.setText(tmp);
320            }
321            mLine5View = (TextView)mView.findViewById(R.id.line5_view);
322            mLine5View.setVisibility(View.GONE);
323        } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
324            mLine1View = (TextView)mView.findViewById(R.id.line1_view);
325            tmp = getString(R.string.upload_fail_line1, mTransInfo.mDeviceName);
326            mLine1View.setText(tmp);
327            mLine2View = (TextView)mView.findViewById(R.id.line2_view);
328            tmp = getString(R.string.upload_fail_line1_2, mTransInfo.mFileName);
329            mLine2View.setText(tmp);
330            mLine3View = (TextView)mView.findViewById(R.id.line3_view);
331            tmp = getString(R.string.download_fail_line3, BluetoothOppUtility.getStatusDescription(
332                    this, mTransInfo.mStatus));
333            mLine3View.setText(tmp);
334            mLine5View = (TextView)mView.findViewById(R.id.line5_view);
335            mLine5View.setVisibility(View.GONE);
336        }
337
338        if (BluetoothShare.isStatusError(mTransInfo.mStatus)) {
339            mProgressTransfer.setVisibility(View.GONE);
340            mPercentView.setVisibility(View.GONE);
341        }
342    }
343
344    public void onClick(DialogInterface dialog, int which) {
345        switch (which) {
346            case DialogInterface.BUTTON_POSITIVE:
347                if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
348                    // "Open" - open receive file
349                    BluetoothOppUtility.openReceivedFile(this, mTransInfo.mFileName,
350                            mTransInfo.mFileType, mTransInfo.mTimeStamp, mUri);
351
352                    // make current transfer "hidden"
353                    BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
354
355                    // clear correspondent notification item
356                    ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
357                            .cancel(mTransInfo.mID);
358                } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
359                    // "try again"
360
361                    // make current transfer "hidden"
362                    BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
363
364                    // clear correspondent notification item
365                    ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
366                            .cancel(mTransInfo.mID);
367
368                    // retry the failed transfer
369                    BluetoothOppUtility.retryTransfer(this, mTransInfo);
370
371                    BluetoothDevice remoteDevice = mAdapter.getRemoteDevice(mTransInfo.mDestAddr);
372
373                    // Display toast message
374                    Toast.makeText(
375                            this,
376                            this.getString(R.string.bt_toast_4, BluetoothOppManager.getInstance(
377                                    this).getDeviceName(remoteDevice)), Toast.LENGTH_SHORT)
378                            .show();
379
380                } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
381                    BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
382                    ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
383                            .cancel(mTransInfo.mID);
384                }
385                break;
386
387            case DialogInterface.BUTTON_NEGATIVE:
388                if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_SEND_ONGOING) {
389                    // "Stop" button
390                    this.getContentResolver().delete(mUri, null, null);
391
392                    String msg = "";
393                    if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
394                        msg = getString(R.string.bt_toast_3, mTransInfo.mDeviceName);
395                    } else if (mWhichDialog == DIALOG_SEND_ONGOING) {
396                        msg = getString(R.string.bt_toast_6, mTransInfo.mDeviceName);
397                    }
398                    Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
399
400                    ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
401                            .cancel(mTransInfo.mID);
402                } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
403
404                    BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
405                }
406                break;
407        }
408        finish();
409    }
410
411    /**
412     * Update progress bar per data got from content provider
413     */
414    private void updateProgressbar() {
415        mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
416        if (mTransInfo == null) {
417            if (V) Log.e(TAG, "Error: Can not get data from db");
418            return;
419        }
420
421        if (mTransInfo.mTotalBytes == 0) {
422            // if Max and progress both equal 0, the progress display 100%.
423            // Below is to fix it.
424            mProgressTransfer.setMax(100);
425        } else {
426            mProgressTransfer.setMax(mTransInfo.mTotalBytes);
427        }
428
429        mProgressTransfer.setProgress(mTransInfo.mCurrentBytes);
430
431        mPercentView.setText(BluetoothOppUtility.formatProgressText(mTransInfo.mTotalBytes,
432                mTransInfo.mCurrentBytes));
433
434        // Handle the case when DIALOG_RECEIVE_ONGOING evolve to
435        // DIALOG_RECEIVE_COMPLETE_SUCCESS/DIALOG_RECEIVE_COMPLETE_FAIL
436        // Handle the case when DIALOG_SEND_ONGOING evolve to
437        // DIALOG_SEND_COMPLETE_SUCCESS/DIALOG_SEND_COMPLETE_FAIL
438        if (!mIsComplete && BluetoothShare.isStatusCompleted(mTransInfo.mStatus)) {
439
440            displayWhichDialog();
441
442            updateButton();
443
444            customizeViewContent();
445        }
446    }
447
448    /**
449     * Update button when one transfer goto complete from ongoing
450     */
451    private void updateButton() {
452        if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
453            mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
454            mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
455                    getString(R.string.download_succ_ok));
456        } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
457            mAlert.setIcon(android.R.drawable.ic_dialog_alert);
458            mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
459            mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
460                    getString(R.string.download_fail_ok));
461        } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
462            mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
463            mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
464                    getString(R.string.upload_succ_ok));
465        } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
466            mAlert.setIcon(android.R.drawable.ic_dialog_alert);
467            mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
468                    getString(R.string.upload_fail_ok));
469            mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setText(
470                    getString(R.string.upload_fail_cancel));
471        }
472    }
473}
474