• 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 static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
36 
37 import android.app.NotificationManager;
38 import android.bluetooth.AlertActivity;
39 import android.bluetooth.BluetoothAdapter;
40 import android.content.DialogInterface;
41 import android.content.Intent;
42 import android.database.ContentObserver;
43 import android.net.Uri;
44 import android.os.Bundle;
45 import android.os.Handler;
46 import android.text.format.Formatter;
47 import android.util.Log;
48 import android.view.View;
49 import android.widget.ProgressBar;
50 import android.widget.TextView;
51 import android.widget.Toast;
52 
53 import com.android.bluetooth.R;
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 View mView = null;
83 
84     private TextView mLine1View, mLine2View, mLine3View, mLine5View;
85 
86     private int mWhichDialog;
87 
88     private BluetoothAdapter mAdapter;
89 
90     // Dialogs definition:
91     // Receive progress dialog
92     public static final int DIALOG_RECEIVE_ONGOING = 0;
93 
94     // Receive complete and success dialog
95     public static final int DIALOG_RECEIVE_COMPLETE_SUCCESS = 1;
96 
97     // Receive complete and fail dialog: will display some fail reason
98     public static final int DIALOG_RECEIVE_COMPLETE_FAIL = 2;
99 
100     // Send progress dialog
101     public static final int DIALOG_SEND_ONGOING = 3;
102 
103     // Send complete and success dialog
104     public static final int DIALOG_SEND_COMPLETE_SUCCESS = 4;
105 
106     // Send complete and fail dialog: will let user retry
107     public static final int DIALOG_SEND_COMPLETE_FAIL = 5;
108 
109     /** Observer to get notified when the content observer's data changes */
110     private BluetoothTransferContentObserver mObserver;
111 
112     // do not update button during activity creating, only update when db
113     // changes after activity created
114     private boolean mNeedUpdateButton = false;
115 
116     private class BluetoothTransferContentObserver extends ContentObserver {
BluetoothTransferContentObserver()117         BluetoothTransferContentObserver() {
118             super(new Handler());
119         }
120 
121         @Override
onChange(boolean selfChange)122         public void onChange(boolean selfChange) {
123             if (V) {
124                 Log.v(TAG, "received db changes.");
125             }
126             mNeedUpdateButton = true;
127             updateProgressbar();
128         }
129     }
130 
131     @Override
onCreate(Bundle savedInstanceState)132     protected void onCreate(Bundle savedInstanceState) {
133         super.onCreate(savedInstanceState);
134 
135         getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
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         mAlertBuilder.setTitle(getString(R.string.download_title));
220         if ((mWhichDialog == DIALOG_RECEIVE_ONGOING) || (mWhichDialog == DIALOG_SEND_ONGOING)) {
221             mAlertBuilder.setPositiveButton(R.string.download_ok, this);
222             mAlertBuilder.setNegativeButton(R.string.download_cancel, this);
223         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
224             mAlertBuilder.setPositiveButton(R.string.download_succ_ok, this);
225         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
226             mAlertBuilder.setIconAttribute(android.R.attr.alertDialogIcon);
227             mAlertBuilder.setPositiveButton(R.string.download_fail_ok, this);
228         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
229             mAlertBuilder.setPositiveButton(R.string.upload_succ_ok, this);
230         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
231             mAlertBuilder.setIconAttribute(android.R.attr.alertDialogIcon);
232             mAlertBuilder.setNegativeButton(R.string.upload_fail_cancel, this);
233         }
234         mAlertBuilder.setView(createView());
235         setupAlert();
236     }
237 
createView()238     private View createView() {
239 
240         mView = getLayoutInflater().inflate(R.layout.file_transfer, null);
241 
242         mProgressTransfer = (ProgressBar) mView.findViewById(R.id.progress_transfer);
243         mPercentView = (TextView) mView.findViewById(R.id.progress_percent);
244 
245         customizeViewContent();
246 
247         // no need update button when activity creating
248         mNeedUpdateButton = false;
249         updateProgressbar();
250 
251         return mView;
252     }
253 
254     /**
255      * customize the content of view
256      */
customizeViewContent()257     private void customizeViewContent() {
258         String tmp;
259 
260         if (mWhichDialog == DIALOG_RECEIVE_ONGOING
261                 || mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
262             mLine1View = (TextView) mView.findViewById(R.id.line1_view);
263             tmp = getString(R.string.download_line1, mTransInfo.mDeviceName);
264             mLine1View.setText(tmp);
265             mLine2View = (TextView) mView.findViewById(R.id.line2_view);
266             tmp = getString(R.string.download_line2, mTransInfo.mFileName);
267             mLine2View.setText(tmp);
268             mLine3View = (TextView) mView.findViewById(R.id.line3_view);
269             tmp = getString(R.string.download_line3,
270                     Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
271             mLine3View.setText(tmp);
272             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
273             if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
274                 tmp = getString(R.string.download_line5);
275             } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
276                 tmp = getString(R.string.download_succ_line5);
277             }
278             mLine5View.setText(tmp);
279         } else if (mWhichDialog == DIALOG_SEND_ONGOING
280                 || mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
281             mLine1View = (TextView) mView.findViewById(R.id.line1_view);
282             tmp = getString(R.string.upload_line1, mTransInfo.mDeviceName);
283             mLine1View.setText(tmp);
284             mLine2View = (TextView) mView.findViewById(R.id.line2_view);
285             tmp = getString(R.string.download_line2, mTransInfo.mFileName);
286             mLine2View.setText(tmp);
287             mLine3View = (TextView) mView.findViewById(R.id.line3_view);
288             tmp = getString(R.string.upload_line3, mTransInfo.mFileType,
289                     Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
290             mLine3View.setText(tmp);
291             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
292             if (mWhichDialog == DIALOG_SEND_ONGOING) {
293                 tmp = getString(R.string.upload_line5);
294             } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
295                 tmp = getString(R.string.upload_succ_line5);
296             }
297             mLine5View.setText(tmp);
298         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
299             if (mTransInfo.mStatus == BluetoothShare.STATUS_ERROR_SDCARD_FULL) {
300                 mLine1View = (TextView) mView.findViewById(R.id.line1_view);
301                 int id = BluetoothOppUtility.deviceHasNoSdCard()
302                         ? R.string.bt_sm_2_1_nosdcard
303                         : R.string.bt_sm_2_1_default;
304                 tmp = getString(id);
305                 mLine1View.setText(tmp);
306                 mLine2View = (TextView) mView.findViewById(R.id.line2_view);
307                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
308                 mLine2View.setText(tmp);
309                 mLine3View = (TextView) mView.findViewById(R.id.line3_view);
310                 tmp = getString(R.string.bt_sm_2_2,
311                         Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
312                 mLine3View.setText(tmp);
313             } else {
314                 mLine1View = (TextView) mView.findViewById(R.id.line1_view);
315                 tmp = getString(R.string.download_fail_line1);
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.download_fail_line3,
322                         BluetoothOppUtility.getStatusDescription(this, mTransInfo.mStatus,
323                                 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,
337                     BluetoothOppUtility.getStatusDescription(this, mTransInfo.mStatus,
338                             mTransInfo.mDeviceName));
339             mLine3View.setText(tmp);
340             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
341             mLine5View.setVisibility(View.GONE);
342         }
343 
344         if (BluetoothShare.isStatusError(mTransInfo.mStatus)) {
345             mProgressTransfer.setVisibility(View.GONE);
346             mPercentView.setVisibility(View.GONE);
347         }
348     }
349 
350     @Override
onClick(DialogInterface dialog, int which)351     public void onClick(DialogInterface dialog, int which) {
352         switch (which) {
353             case DialogInterface.BUTTON_POSITIVE:
354                 if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
355                     // "Open" - open receive file
356                     BluetoothOppUtility.openReceivedFile(this, mTransInfo.mFileName,
357                             mTransInfo.mFileType, mTransInfo.mTimeStamp, mUri);
358 
359                     // make current transfer "hidden"
360                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
361 
362                     // clear correspondent notification item
363                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
364                             mTransInfo.mID);
365                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
366                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
367                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
368                             mTransInfo.mID);
369                 }
370                 break;
371 
372             case DialogInterface.BUTTON_NEGATIVE:
373                 if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_SEND_ONGOING) {
374                     // "Stop" button
375                     this.getContentResolver().delete(mUri, null, null);
376 
377                     String msg = "";
378                     if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
379                         msg = getString(R.string.bt_toast_3, mTransInfo.mDeviceName);
380                     } else if (mWhichDialog == DIALOG_SEND_ONGOING) {
381                         msg = getString(R.string.bt_toast_6, mTransInfo.mDeviceName);
382                     }
383                     Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
384 
385                     ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(
386                             mTransInfo.mID);
387                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
388 
389                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
390                 }
391                 break;
392         }
393         finish();
394     }
395 
396     /**
397      * Update progress bar per data got from content provider
398      */
updateProgressbar()399     private void updateProgressbar() {
400         mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
401         if (mTransInfo == null) {
402             if (V) {
403                 Log.e(TAG, "Error: Can not get data from db");
404             }
405             return;
406         }
407 
408         // Set Transfer Max as 100. Percentage calculation would be done in setProgress API
409         mProgressTransfer.setMax(100);
410 
411         if (mTransInfo.mTotalBytes != 0) {
412             if (V) {
413                 Log.v(TAG, "mCurrentBytes: " + mTransInfo.mCurrentBytes + " mTotalBytes: "
414                         + mTransInfo.mTotalBytes + " (" + (int) ((mTransInfo.mCurrentBytes * 100)
415                         / mTransInfo.mTotalBytes) + "%)");
416             }
417             mProgressTransfer.setProgress(
418                     (int) ((mTransInfo.mCurrentBytes * 100) / mTransInfo.mTotalBytes));
419         } else {
420             mProgressTransfer.setProgress(100);
421         }
422 
423         mPercentView.setText(BluetoothOppUtility.formatProgressText(mTransInfo.mTotalBytes,
424                 mTransInfo.mCurrentBytes));
425 
426         // Handle the case when DIALOG_RECEIVE_ONGOING evolve to
427         // DIALOG_RECEIVE_COMPLETE_SUCCESS/DIALOG_RECEIVE_COMPLETE_FAIL
428         // Handle the case when DIALOG_SEND_ONGOING evolve to
429         // DIALOG_SEND_COMPLETE_SUCCESS/DIALOG_SEND_COMPLETE_FAIL
430         if (!mIsComplete && BluetoothShare.isStatusCompleted(mTransInfo.mStatus)
431                 && mNeedUpdateButton) {
432             if (mObserver != null) {
433                 getContentResolver().unregisterContentObserver(mObserver);
434                 mObserver = null;
435             }
436             displayWhichDialog();
437             updateButton();
438             customizeViewContent();
439         }
440     }
441 
442     /**
443      * Update button when one transfer goto complete from ongoing
444      */
updateButton()445     private void updateButton() {
446         if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
447             changeButtonVisibility(DialogInterface.BUTTON_NEGATIVE, View.GONE);
448             changeButtonText(
449                     DialogInterface.BUTTON_POSITIVE,
450                     getString(R.string.download_succ_ok));
451         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
452             changeIconAttribute(android.R.attr.alertDialogIcon);
453             changeButtonVisibility(DialogInterface.BUTTON_NEGATIVE, View.GONE);
454             changeButtonText(
455                     DialogInterface.BUTTON_POSITIVE,
456                     getString(R.string.download_fail_ok));
457         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
458             changeButtonVisibility(DialogInterface.BUTTON_NEGATIVE, View.GONE);
459             changeButtonText(
460                     DialogInterface.BUTTON_POSITIVE,
461                     getString(R.string.upload_succ_ok));
462         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
463             changeIconAttribute(android.R.attr.alertDialogIcon);
464             changeButtonText(
465                     DialogInterface.BUTTON_NEGATIVE,
466                     getString(R.string.upload_fail_cancel));
467         }
468     }
469 }
470