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 { 120 public BluetoothTransferContentObserver() { 121 super(new Handler()); 122 } 123 124 @Override 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 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 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 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 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 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 */ 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 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 */ 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 */ 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