• 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.mTitle = getString(R.string.download_title);
215 
216         if ((mWhichDialog == DIALOG_RECEIVE_ONGOING) || (mWhichDialog == DIALOG_SEND_ONGOING)) {
217             mPara.mPositiveButtonText = getString(R.string.download_ok);
218             mPara.mPositiveButtonListener = this;
219             mPara.mNegativeButtonText = getString(R.string.download_cancel);
220             mPara.mNegativeButtonListener = this;
221         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
222             mPara.mPositiveButtonText = getString(R.string.download_succ_ok);
223             mPara.mPositiveButtonListener = this;
224         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
225             mPara.mIconAttrId = android.R.attr.alertDialogIcon;
226             mPara.mPositiveButtonText = getString(R.string.download_fail_ok);
227             mPara.mPositiveButtonListener = this;
228         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
229             mPara.mPositiveButtonText = getString(R.string.upload_succ_ok);
230             mPara.mPositiveButtonListener = this;
231         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
232             mPara.mIconAttrId = android.R.attr.alertDialogIcon;
233             mPara.mPositiveButtonText = getString(R.string.upload_fail_ok);
234             mPara.mPositiveButtonListener = this;
235             mPara.mNegativeButtonText = getString(R.string.upload_fail_cancel);
236             mPara.mNegativeButtonListener = this;
237         }
238         mPara.mView = createView();
239         setupAlert();
240     }
241 
createView()242     private View createView() {
243 
244         mView = getLayoutInflater().inflate(R.layout.file_transfer, null);
245 
246         mProgressTransfer = (ProgressBar)mView.findViewById(R.id.progress_transfer);
247         mPercentView = (TextView)mView.findViewById(R.id.progress_percent);
248 
249         customizeViewContent();
250 
251         // no need update button when activity creating
252         mNeedUpdateButton = false;
253         updateProgressbar();
254 
255         return mView;
256     }
257 
258     /**
259      * customize the content of view
260      */
customizeViewContent()261     private void customizeViewContent() {
262         String tmp;
263 
264         if (mWhichDialog == DIALOG_RECEIVE_ONGOING
265                 || mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
266             mLine1View = (TextView)mView.findViewById(R.id.line1_view);
267             tmp = getString(R.string.download_line1, mTransInfo.mDeviceName);
268             mLine1View.setText(tmp);
269             mLine2View = (TextView)mView.findViewById(R.id.line2_view);
270             tmp = getString(R.string.download_line2, mTransInfo.mFileName);
271             mLine2View.setText(tmp);
272             mLine3View = (TextView)mView.findViewById(R.id.line3_view);
273             tmp = getString(R.string.download_line3, Formatter.formatFileSize(this,
274                     mTransInfo.mTotalBytes));
275             mLine3View.setText(tmp);
276             mLine5View = (TextView)mView.findViewById(R.id.line5_view);
277             if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
278                 tmp = getString(R.string.download_line5);
279             } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
280                 tmp = getString(R.string.download_succ_line5);
281             }
282             mLine5View.setText(tmp);
283         } else if (mWhichDialog == DIALOG_SEND_ONGOING
284                 || mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
285             mLine1View = (TextView)mView.findViewById(R.id.line1_view);
286             tmp = getString(R.string.upload_line1, mTransInfo.mDeviceName);
287             mLine1View.setText(tmp);
288             mLine2View = (TextView)mView.findViewById(R.id.line2_view);
289             tmp = getString(R.string.download_line2, mTransInfo.mFileName);
290             mLine2View.setText(tmp);
291             mLine3View = (TextView)mView.findViewById(R.id.line3_view);
292             tmp = getString(R.string.upload_line3, mTransInfo.mFileType, Formatter.formatFileSize(
293                     this, mTransInfo.mTotalBytes));
294             mLine3View.setText(tmp);
295             mLine5View = (TextView)mView.findViewById(R.id.line5_view);
296             if (mWhichDialog == DIALOG_SEND_ONGOING) {
297                 tmp = getString(R.string.upload_line5);
298             } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
299                 tmp = getString(R.string.upload_succ_line5);
300             }
301             mLine5View.setText(tmp);
302         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
303             if (mTransInfo.mStatus == BluetoothShare.STATUS_ERROR_SDCARD_FULL) {
304                 mLine1View = (TextView)mView.findViewById(R.id.line1_view);
305                 tmp = getString(R.string.bt_sm_2_1, mTransInfo.mDeviceName);
306                 mLine1View.setText(tmp);
307                 mLine2View = (TextView)mView.findViewById(R.id.line2_view);
308                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
309                 mLine2View.setText(tmp);
310                 mLine3View = (TextView)mView.findViewById(R.id.line3_view);
311                 tmp = getString(R.string.bt_sm_2_2, Formatter.formatFileSize(this,
312                         mTransInfo.mTotalBytes));
313                 mLine3View.setText(tmp);
314             } else {
315                 mLine1View = (TextView)mView.findViewById(R.id.line1_view);
316                 tmp = getString(R.string.download_fail_line1);
317                 mLine1View.setText(tmp);
318                 mLine2View = (TextView)mView.findViewById(R.id.line2_view);
319                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
320                 mLine2View.setText(tmp);
321                 mLine3View = (TextView)mView.findViewById(R.id.line3_view);
322                 tmp = getString(R.string.download_fail_line3, BluetoothOppUtility
323                         .getStatusDescription(this, mTransInfo.mStatus, mTransInfo.mDeviceName));
324                 mLine3View.setText(tmp);
325             }
326             mLine5View = (TextView)mView.findViewById(R.id.line5_view);
327             mLine5View.setVisibility(View.GONE);
328         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
329             mLine1View = (TextView)mView.findViewById(R.id.line1_view);
330             tmp = getString(R.string.upload_fail_line1, mTransInfo.mDeviceName);
331             mLine1View.setText(tmp);
332             mLine2View = (TextView)mView.findViewById(R.id.line2_view);
333             tmp = getString(R.string.upload_fail_line1_2, mTransInfo.mFileName);
334             mLine2View.setText(tmp);
335             mLine3View = (TextView)mView.findViewById(R.id.line3_view);
336             tmp = getString(R.string.download_fail_line3, BluetoothOppUtility.getStatusDescription(
337                     this, mTransInfo.mStatus, mTransInfo.mDeviceName));
338             mLine3View.setText(tmp);
339             mLine5View = (TextView)mView.findViewById(R.id.line5_view);
340             mLine5View.setVisibility(View.GONE);
341         }
342 
343         if (BluetoothShare.isStatusError(mTransInfo.mStatus)) {
344             mProgressTransfer.setVisibility(View.GONE);
345             mPercentView.setVisibility(View.GONE);
346         }
347     }
348 
onClick(DialogInterface dialog, int which)349     public void onClick(DialogInterface dialog, int which) {
350         switch (which) {
351             case DialogInterface.BUTTON_POSITIVE:
352                 if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
353                     // "Open" - open receive file
354                     BluetoothOppUtility.openReceivedFile(this, mTransInfo.mFileName,
355                             mTransInfo.mFileType, mTransInfo.mTimeStamp, mUri);
356 
357                     // make current transfer "hidden"
358                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
359 
360                     // clear correspondent notification item
361                     ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
362                             .cancel(mTransInfo.mID);
363                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
364                     // "try again"
365 
366                     // make current transfer "hidden"
367                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
368 
369                     // clear correspondent notification item
370                     ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
371                             .cancel(mTransInfo.mID);
372 
373                     // retry the failed transfer
374                     BluetoothOppUtility.retryTransfer(this, mTransInfo);
375 
376                     BluetoothDevice remoteDevice = mAdapter.getRemoteDevice(mTransInfo.mDestAddr);
377 
378                     // Display toast message
379                     Toast.makeText(
380                             this,
381                             this.getString(R.string.bt_toast_4, BluetoothOppManager.getInstance(
382                                     this).getDeviceName(remoteDevice)), Toast.LENGTH_SHORT)
383                             .show();
384 
385                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
386                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
387                     ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
388                             .cancel(mTransInfo.mID);
389                 }
390                 break;
391 
392             case DialogInterface.BUTTON_NEGATIVE:
393                 if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_SEND_ONGOING) {
394                     // "Stop" button
395                     this.getContentResolver().delete(mUri, null, null);
396 
397                     String msg = "";
398                     if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
399                         msg = getString(R.string.bt_toast_3, mTransInfo.mDeviceName);
400                     } else if (mWhichDialog == DIALOG_SEND_ONGOING) {
401                         msg = getString(R.string.bt_toast_6, mTransInfo.mDeviceName);
402                     }
403                     Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
404 
405                     ((NotificationManager)getSystemService(NOTIFICATION_SERVICE))
406                             .cancel(mTransInfo.mID);
407                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
408 
409                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
410                 }
411                 break;
412         }
413         finish();
414     }
415 
416     /**
417      * Update progress bar per data got from content provider
418      */
updateProgressbar()419     private void updateProgressbar() {
420         mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
421         if (mTransInfo == null) {
422             if (V) Log.e(TAG, "Error: Can not get data from db");
423             return;
424         }
425 
426         // Set Transfer Max as 100. Percentage calculation would be done in setProgress API
427         mProgressTransfer.setMax(100);
428 
429         if (mTransInfo.mTotalBytes != 0) {
430             if (V) Log.v(TAG, "mCurrentBytes: " + mTransInfo.mCurrentBytes +
431                 " mTotalBytes: " + mTransInfo.mTotalBytes + " (" +
432                 (int)((mTransInfo.mCurrentBytes * 100) / mTransInfo.mTotalBytes) + "%)");
433             mProgressTransfer.setProgress((int)((mTransInfo.mCurrentBytes * 100) /
434                 mTransInfo.mTotalBytes));
435         } else {
436             mProgressTransfer.setProgress(100);
437         }
438 
439         mPercentView.setText(BluetoothOppUtility.formatProgressText(mTransInfo.mTotalBytes,
440                 mTransInfo.mCurrentBytes));
441 
442         // Handle the case when DIALOG_RECEIVE_ONGOING evolve to
443         // DIALOG_RECEIVE_COMPLETE_SUCCESS/DIALOG_RECEIVE_COMPLETE_FAIL
444         // Handle the case when DIALOG_SEND_ONGOING evolve to
445         // DIALOG_SEND_COMPLETE_SUCCESS/DIALOG_SEND_COMPLETE_FAIL
446         if (!mIsComplete && BluetoothShare.isStatusCompleted(mTransInfo.mStatus)
447                 && mNeedUpdateButton) {
448             displayWhichDialog();
449             updateButton();
450             customizeViewContent();
451         }
452     }
453 
454     /**
455      * Update button when one transfer goto complete from ongoing
456      */
updateButton()457     private void updateButton() {
458         if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
459             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
460             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
461                     getString(R.string.download_succ_ok));
462         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
463             mAlert.setIcon(mAlert.getIconAttributeResId(android.R.attr.alertDialogIcon));
464             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
465             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
466                     getString(R.string.download_fail_ok));
467         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
468             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
469             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
470                     getString(R.string.upload_succ_ok));
471         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
472             mAlert.setIcon(mAlert.getIconAttributeResId(android.R.attr.alertDialogIcon));
473             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
474                     getString(R.string.upload_fail_ok));
475             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setText(
476                     getString(R.string.upload_fail_cancel));
477         }
478     }
479 }
480