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