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