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