• 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                 int id = BluetoothOppUtility.deviceHasNoSdCard()
313                         ? R.string.bt_sm_2_1_nosdcard
314                         : R.string.bt_sm_2_1_default;
315                 tmp = getString(id);
316                 mLine1View.setText(tmp);
317                 mLine2View = (TextView) mView.findViewById(R.id.line2_view);
318                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
319                 mLine2View.setText(tmp);
320                 mLine3View = (TextView) mView.findViewById(R.id.line3_view);
321                 tmp = getString(R.string.bt_sm_2_2,
322                         Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
323                 mLine3View.setText(tmp);
324             } else {
325                 mLine1View = (TextView) mView.findViewById(R.id.line1_view);
326                 tmp = getString(R.string.download_fail_line1);
327                 mLine1View.setText(tmp);
328                 mLine2View = (TextView) mView.findViewById(R.id.line2_view);
329                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
330                 mLine2View.setText(tmp);
331                 mLine3View = (TextView) mView.findViewById(R.id.line3_view);
332                 tmp = getString(R.string.download_fail_line3,
333                         BluetoothOppUtility.getStatusDescription(this, mTransInfo.mStatus,
334                                 mTransInfo.mDeviceName));
335                 mLine3View.setText(tmp);
336             }
337             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
338             mLine5View.setVisibility(View.GONE);
339         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
340             mLine1View = (TextView) mView.findViewById(R.id.line1_view);
341             tmp = getString(R.string.upload_fail_line1, mTransInfo.mDeviceName);
342             mLine1View.setText(tmp);
343             mLine2View = (TextView) mView.findViewById(R.id.line2_view);
344             tmp = getString(R.string.upload_fail_line1_2, mTransInfo.mFileName);
345             mLine2View.setText(tmp);
346             mLine3View = (TextView) mView.findViewById(R.id.line3_view);
347             tmp = getString(R.string.download_fail_line3,
348                     BluetoothOppUtility.getStatusDescription(this, mTransInfo.mStatus,
349                             mTransInfo.mDeviceName));
350             mLine3View.setText(tmp);
351             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
352             mLine5View.setVisibility(View.GONE);
353         }
354 
355         if (BluetoothShare.isStatusError(mTransInfo.mStatus)) {
356             mProgressTransfer.setVisibility(View.GONE);
357             mPercentView.setVisibility(View.GONE);
358         }
359     }
360 
361     @Override
onClick(DialogInterface dialog, int which)362     public void onClick(DialogInterface dialog, int which) {
363         switch (which) {
364             case DialogInterface.BUTTON_POSITIVE:
365                 if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
366                     // "Open" - open receive file
367                     BluetoothOppUtility.openReceivedFile(this, mTransInfo.mFileName,
368                             mTransInfo.mFileType, mTransInfo.mTimeStamp, mUri);
369 
370                     // make current transfer "hidden"
371                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
372 
373                     // clear correspondent notification item
374                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
375                             mTransInfo.mID);
376                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
377                     // "try again"
378 
379                     // make current transfer "hidden"
380                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
381 
382                     // clear correspondent notification item
383                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
384                             mTransInfo.mID);
385 
386                     // retry the failed transfer
387                     Uri uri = BluetoothOppUtility.originalUri(Uri.parse(mTransInfo.mFileUri));
388                     BluetoothOppSendFileInfo sendFileInfo =
389                             BluetoothOppSendFileInfo.generateFileInfo(BluetoothOppTransferActivity
390                             .this, uri, mTransInfo.mFileType, false);
391                     uri = BluetoothOppUtility.generateUri(uri, sendFileInfo);
392                     BluetoothOppUtility.putSendFileInfo(uri, sendFileInfo);
393                     mTransInfo.mFileUri = uri.toString();
394                     BluetoothOppUtility.retryTransfer(this, mTransInfo);
395 
396                     BluetoothDevice remoteDevice = mAdapter.getRemoteDevice(mTransInfo.mDestAddr);
397 
398                     // Display toast message
399                     Toast.makeText(this, this.getString(R.string.bt_toast_4,
400                             BluetoothOppManager.getInstance(this).getDeviceName(remoteDevice)),
401                             Toast.LENGTH_SHORT).show();
402 
403                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
404                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
405                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
406                             mTransInfo.mID);
407                 }
408                 break;
409 
410             case DialogInterface.BUTTON_NEGATIVE:
411                 if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_SEND_ONGOING) {
412                     // "Stop" button
413                     this.getContentResolver().delete(mUri, null, null);
414 
415                     String msg = "";
416                     if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
417                         msg = getString(R.string.bt_toast_3, mTransInfo.mDeviceName);
418                     } else if (mWhichDialog == DIALOG_SEND_ONGOING) {
419                         msg = getString(R.string.bt_toast_6, mTransInfo.mDeviceName);
420                     }
421                     Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
422 
423                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
424                             mTransInfo.mID);
425                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
426 
427                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
428                 }
429                 break;
430         }
431         finish();
432     }
433 
434     /**
435      * Update progress bar per data got from content provider
436      */
updateProgressbar()437     private void updateProgressbar() {
438         mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
439         if (mTransInfo == null) {
440             if (V) {
441                 Log.e(TAG, "Error: Can not get data from db");
442             }
443             return;
444         }
445 
446         // Set Transfer Max as 100. Percentage calculation would be done in setProgress API
447         mProgressTransfer.setMax(100);
448 
449         if (mTransInfo.mTotalBytes != 0) {
450             if (V) {
451                 Log.v(TAG, "mCurrentBytes: " + mTransInfo.mCurrentBytes + " mTotalBytes: "
452                         + mTransInfo.mTotalBytes + " (" + (int) ((mTransInfo.mCurrentBytes * 100)
453                         / mTransInfo.mTotalBytes) + "%)");
454             }
455             mProgressTransfer.setProgress(
456                     (int) ((mTransInfo.mCurrentBytes * 100) / mTransInfo.mTotalBytes));
457         } else {
458             mProgressTransfer.setProgress(100);
459         }
460 
461         mPercentView.setText(BluetoothOppUtility.formatProgressText(mTransInfo.mTotalBytes,
462                 mTransInfo.mCurrentBytes));
463 
464         // Handle the case when DIALOG_RECEIVE_ONGOING evolve to
465         // DIALOG_RECEIVE_COMPLETE_SUCCESS/DIALOG_RECEIVE_COMPLETE_FAIL
466         // Handle the case when DIALOG_SEND_ONGOING evolve to
467         // DIALOG_SEND_COMPLETE_SUCCESS/DIALOG_SEND_COMPLETE_FAIL
468         if (!mIsComplete && BluetoothShare.isStatusCompleted(mTransInfo.mStatus)
469                 && mNeedUpdateButton) {
470             if (mObserver != null) {
471                 getContentResolver().unregisterContentObserver(mObserver);
472                 mObserver = null;
473             }
474             displayWhichDialog();
475             updateButton();
476             customizeViewContent();
477         }
478     }
479 
480     /**
481      * Update button when one transfer goto complete from ongoing
482      */
updateButton()483     private void updateButton() {
484         if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
485             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
486             mAlert.getButton(DialogInterface.BUTTON_POSITIVE)
487                     .setText(getString(R.string.download_succ_ok));
488         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
489             mAlert.setIcon(mAlert.getIconAttributeResId(android.R.attr.alertDialogIcon));
490             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
491             mAlert.getButton(DialogInterface.BUTTON_POSITIVE)
492                     .setText(getString(R.string.download_fail_ok));
493         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
494             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
495             mAlert.getButton(DialogInterface.BUTTON_POSITIVE)
496                     .setText(getString(R.string.upload_succ_ok));
497         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
498             mAlert.setIcon(mAlert.getIconAttributeResId(android.R.attr.alertDialogIcon));
499             mAlert.getButton(DialogInterface.BUTTON_POSITIVE)
500                     .setText(getString(R.string.upload_fail_ok));
501             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE)
502                     .setText(getString(R.string.upload_fail_cancel));
503         }
504     }
505 }
506