• 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 import com.google.common.annotations.VisibleForTesting;
56 
57 /**
58  * Handle all transfer related dialogs: -Ongoing transfer -Receiving one file
59  * dialog -Sending one file dialog -sending multiple files dialog -Complete
60  * transfer -receive -receive success, will trigger corresponding handler
61  * -receive fail dialog -send -send success dialog -send fail dialog -Other
62  * dialogs - - DIALOG_RECEIVE_ONGOING will transition to
63  * DIALOG_RECEIVE_COMPLETE_SUCCESS or DIALOG_RECEIVE_COMPLETE_FAIL
64  * DIALOG_SEND_ONGOING will transition to DIALOG_SEND_COMPLETE_SUCCESS or
65  * DIALOG_SEND_COMPLETE_FAIL
66  */
67 public class BluetoothOppTransferActivity extends AlertActivity
68         implements DialogInterface.OnClickListener {
69     private static final String TAG = "BluetoothOppTransferActivity";
70     private static final boolean D = Constants.DEBUG;
71     private static final boolean V = Constants.VERBOSE;
72 
73     private Uri mUri;
74 
75     // ongoing transfer-0 complete transfer-1
76     boolean mIsComplete;
77 
78     private BluetoothOppTransferInfo mTransInfo;
79 
80     private ProgressBar mProgressTransfer;
81 
82     private TextView mPercentView;
83 
84     private View mView = null;
85 
86     private TextView mLine1View, mLine2View, mLine3View, mLine5View;
87 
88     @VisibleForTesting
89     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         BluetoothTransferContentObserver() {
121             super(new Handler());
122         }
123 
124         @Override
onChange(boolean selfChange)125         public void onChange(boolean selfChange) {
126             if (V) {
127                 Log.v(TAG, "received db changes.");
128             }
129             mNeedUpdateButton = true;
130             updateProgressbar();
131         }
132     }
133 
134     @Override
onCreate(Bundle savedInstanceState)135     protected void onCreate(Bundle savedInstanceState) {
136         super.onCreate(savedInstanceState);
137 
138         getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
139         Intent intent = getIntent();
140         mUri = intent.getData();
141 
142         mTransInfo = new BluetoothOppTransferInfo();
143         mTransInfo = BluetoothOppUtility.queryRecord(this, mUri);
144         if (mTransInfo == null) {
145             if (V) {
146                 Log.e(TAG, "Error: Can not get data from db");
147             }
148             finish();
149             return;
150         }
151 
152         mIsComplete = BluetoothShare.isStatusCompleted(mTransInfo.mStatus);
153 
154         displayWhichDialog();
155 
156         // update progress bar for ongoing transfer
157         if (!mIsComplete) {
158             mObserver = new BluetoothTransferContentObserver();
159             getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true,
160                     mObserver);
161         }
162 
163         if (mWhichDialog != DIALOG_SEND_ONGOING && mWhichDialog != DIALOG_RECEIVE_ONGOING) {
164             // set this record to INVISIBLE
165             BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
166         }
167 
168         mAdapter = BluetoothAdapter.getDefaultAdapter();
169 
170         // Set up the "dialog"
171         setUpDialog();
172     }
173 
174     @Override
onDestroy()175     protected void onDestroy() {
176         if (D) {
177             Log.d(TAG, "onDestroy()");
178         }
179 
180         if (mObserver != null) {
181             getContentResolver().unregisterContentObserver(mObserver);
182         }
183         super.onDestroy();
184     }
185 
displayWhichDialog()186     private void displayWhichDialog() {
187         int direction = mTransInfo.mDirection;
188         boolean isSuccess = BluetoothShare.isStatusSuccess(mTransInfo.mStatus);
189         boolean isComplete = BluetoothShare.isStatusCompleted(mTransInfo.mStatus);
190 
191         if (direction == BluetoothShare.DIRECTION_INBOUND) {
192             if (isComplete) {
193                 if (isSuccess) {
194                     // should not go here
195                     mWhichDialog = DIALOG_RECEIVE_COMPLETE_SUCCESS;
196                 } else if (!isSuccess) {
197                     mWhichDialog = DIALOG_RECEIVE_COMPLETE_FAIL;
198                 }
199             } else if (!isComplete) {
200                 mWhichDialog = DIALOG_RECEIVE_ONGOING;
201             }
202         } else if (direction == BluetoothShare.DIRECTION_OUTBOUND) {
203             if (isComplete) {
204                 if (isSuccess) {
205                     mWhichDialog = DIALOG_SEND_COMPLETE_SUCCESS;
206 
207                 } else if (!isSuccess) {
208                     mWhichDialog = DIALOG_SEND_COMPLETE_FAIL;
209                 }
210             } else if (!isComplete) {
211                 mWhichDialog = DIALOG_SEND_ONGOING;
212             }
213         }
214 
215         if (V) {
216             Log.v(TAG, " WhichDialog/dir/isComplete/failOrSuccess" + mWhichDialog + direction
217                     + isComplete + isSuccess);
218         }
219     }
220 
setUpDialog()221     private void setUpDialog() {
222         mAlertBuilder.setTitle(getString(R.string.download_title));
223         if ((mWhichDialog == DIALOG_RECEIVE_ONGOING) || (mWhichDialog == DIALOG_SEND_ONGOING)) {
224             mAlertBuilder.setPositiveButton(R.string.download_ok, this);
225             mAlertBuilder.setNegativeButton(R.string.download_cancel, this);
226         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
227             mAlertBuilder.setPositiveButton(R.string.download_succ_ok, this);
228         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
229             mAlertBuilder.setIconAttribute(android.R.attr.alertDialogIcon);
230             mAlertBuilder.setPositiveButton(R.string.download_fail_ok, this);
231         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
232             mAlertBuilder.setPositiveButton(R.string.upload_succ_ok, this);
233         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
234             mAlertBuilder.setIconAttribute(android.R.attr.alertDialogIcon);
235             mAlertBuilder.setNegativeButton(R.string.upload_fail_cancel, this);
236         }
237         mAlertBuilder.setView(createView());
238         setupAlert();
239     }
240 
createView()241     private View createView() {
242 
243         mView = getLayoutInflater().inflate(R.layout.file_transfer, null);
244 
245         mProgressTransfer = (ProgressBar) mView.findViewById(R.id.progress_transfer);
246         mPercentView = (TextView) mView.findViewById(R.id.progress_percent);
247 
248         customizeViewContent();
249 
250         // no need update button when activity creating
251         mNeedUpdateButton = false;
252         updateProgressbar();
253 
254         return mView;
255     }
256 
257     /**
258      * customize the content of view
259      */
customizeViewContent()260     private void customizeViewContent() {
261         String tmp;
262 
263         if (mWhichDialog == DIALOG_RECEIVE_ONGOING
264                 || mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
265             mLine1View = (TextView) mView.findViewById(R.id.line1_view);
266             tmp = getString(R.string.download_line1, mTransInfo.mDeviceName);
267             mLine1View.setText(tmp);
268             mLine2View = (TextView) mView.findViewById(R.id.line2_view);
269             tmp = getString(R.string.download_line2, mTransInfo.mFileName);
270             mLine2View.setText(tmp);
271             mLine3View = (TextView) mView.findViewById(R.id.line3_view);
272             tmp = getString(R.string.download_line3,
273                     Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
274             mLine3View.setText(tmp);
275             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
276             if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
277                 tmp = getString(R.string.download_line5);
278             } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
279                 tmp = getString(R.string.download_succ_line5);
280             }
281             mLine5View.setText(tmp);
282         } else if (mWhichDialog == DIALOG_SEND_ONGOING
283                 || mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
284             mLine1View = (TextView) mView.findViewById(R.id.line1_view);
285             tmp = getString(R.string.upload_line1, mTransInfo.mDeviceName);
286             mLine1View.setText(tmp);
287             mLine2View = (TextView) mView.findViewById(R.id.line2_view);
288             tmp = getString(R.string.download_line2, mTransInfo.mFileName);
289             mLine2View.setText(tmp);
290             mLine3View = (TextView) mView.findViewById(R.id.line3_view);
291             tmp = getString(R.string.upload_line3, mTransInfo.mFileType,
292                     Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
293             mLine3View.setText(tmp);
294             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
295             if (mWhichDialog == DIALOG_SEND_ONGOING) {
296                 tmp = getString(R.string.upload_line5);
297             } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
298                 tmp = getString(R.string.upload_succ_line5);
299             }
300             mLine5View.setText(tmp);
301         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
302             if (mTransInfo.mStatus == BluetoothShare.STATUS_ERROR_SDCARD_FULL) {
303                 mLine1View = (TextView) mView.findViewById(R.id.line1_view);
304                 int id = BluetoothOppUtility.deviceHasNoSdCard()
305                         ? R.string.bt_sm_2_1_nosdcard
306                         : R.string.bt_sm_2_1_default;
307                 tmp = getString(id);
308                 mLine1View.setText(tmp);
309                 mLine2View = (TextView) mView.findViewById(R.id.line2_view);
310                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
311                 mLine2View.setText(tmp);
312                 mLine3View = (TextView) mView.findViewById(R.id.line3_view);
313                 tmp = getString(R.string.bt_sm_2_2,
314                         Formatter.formatFileSize(this, mTransInfo.mTotalBytes));
315                 mLine3View.setText(tmp);
316             } else {
317                 mLine1View = (TextView) mView.findViewById(R.id.line1_view);
318                 tmp = getString(R.string.download_fail_line1);
319                 mLine1View.setText(tmp);
320                 mLine2View = (TextView) mView.findViewById(R.id.line2_view);
321                 tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName);
322                 mLine2View.setText(tmp);
323                 mLine3View = (TextView) mView.findViewById(R.id.line3_view);
324                 tmp = getString(R.string.download_fail_line3,
325                         BluetoothOppUtility.getStatusDescription(this, mTransInfo.mStatus,
326                                 mTransInfo.mDeviceName));
327                 mLine3View.setText(tmp);
328             }
329             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
330             mLine5View.setVisibility(View.GONE);
331         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
332             mLine1View = (TextView) mView.findViewById(R.id.line1_view);
333             tmp = getString(R.string.upload_fail_line1, mTransInfo.mDeviceName);
334             mLine1View.setText(tmp);
335             mLine2View = (TextView) mView.findViewById(R.id.line2_view);
336             tmp = getString(R.string.upload_fail_line1_2, mTransInfo.mFileName);
337             mLine2View.setText(tmp);
338             mLine3View = (TextView) mView.findViewById(R.id.line3_view);
339             tmp = getString(R.string.download_fail_line3,
340                     BluetoothOppUtility.getStatusDescription(this, mTransInfo.mStatus,
341                             mTransInfo.mDeviceName));
342             mLine3View.setText(tmp);
343             mLine5View = (TextView) mView.findViewById(R.id.line5_view);
344             mLine5View.setVisibility(View.GONE);
345         }
346 
347         if (BluetoothShare.isStatusError(mTransInfo.mStatus)) {
348             mProgressTransfer.setVisibility(View.GONE);
349             mPercentView.setVisibility(View.GONE);
350         }
351     }
352 
353     @Override
onClick(DialogInterface dialog, int which)354     public void onClick(DialogInterface dialog, int which) {
355         switch (which) {
356             case DialogInterface.BUTTON_POSITIVE:
357                 if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
358                     // "Open" - open receive file
359                     BluetoothOppUtility.openReceivedFile(this, mTransInfo.mFileName,
360                             mTransInfo.mFileType, mTransInfo.mTimeStamp, mUri);
361 
362                     // make current transfer "hidden"
363                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
364 
365                     // clear correspondent notification item
366                     getSystemService(NotificationManager.class).cancel(mTransInfo.mID);
367                 } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
368                     BluetoothOppUtility.updateVisibilityToHidden(this, mUri);
369                     getSystemService(NotificationManager.class).cancel(mTransInfo.mID);
370                 }
371                 break;
372 
373             case DialogInterface.BUTTON_NEGATIVE:
374                 if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_SEND_ONGOING) {
375                     // "Stop" button
376                     this.getContentResolver().delete(mUri, null, null);
377 
378                     String msg = "";
379                     if (mWhichDialog == DIALOG_RECEIVE_ONGOING) {
380                         msg = getString(R.string.bt_toast_3, mTransInfo.mDeviceName);
381                     } else if (mWhichDialog == DIALOG_SEND_ONGOING) {
382                         msg = getString(R.string.bt_toast_6, mTransInfo.mDeviceName);
383                     }
384                     Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
385 
386                     getSystemService(NotificationManager.class).cancel(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