• 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 com.android.bluetooth.R;
36 
37 import android.bluetooth.BluetoothAdapter;
38 import android.bluetooth.BluetoothDevice;
39 import android.content.DialogInterface;
40 import android.content.Intent;
41 import android.net.Uri;
42 import android.os.Bundle;
43 import android.os.Handler;
44 import android.util.Log;
45 import android.view.View;
46 import android.widget.TextView;
47 import android.widget.Toast;
48 import android.database.ContentObserver;
49 import android.widget.ProgressBar;
50 
51 import com.android.internal.app.AlertActivity;
52 import com.android.internal.app.AlertController;
53 import android.app.NotificationManager;
54 import 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  */
66 public 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 {
BluetoothTransferContentObserver()120         public BluetoothTransferContentObserver() {
121             super(new Handler());
122         }
123 
124         @Override
onChange(boolean selfChange)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
onCreate(Bundle savedInstanceState)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
onDestroy()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 
displayWhichDialog()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 
setUpDialog()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.mIconId = android.R.drawable.ic_dialog_alert;
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.mIconId = android.R.drawable.ic_dialog_alert;
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 
createView()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      */
customizeViewContent()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 
onClick(DialogInterface dialog, int which)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      */
updateProgressbar()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      */
updateButton()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(android.R.drawable.ic_dialog_alert);
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(android.R.drawable.ic_dialog_alert);
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