/* * Copyright (c) 2008-2009, Motorola, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * - Neither the name of the Motorola, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.android.bluetooth.opp; import com.android.bluetooth.R; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; import android.database.ContentObserver; import android.widget.ProgressBar; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; import android.app.NotificationManager; import android.text.format.Formatter; /** * Handle all transfer related dialogs: -Ongoing transfer -Receiving one file * dialog -Sending one file dialog -sending multiple files dialog -Complete * transfer -receive -receive success, will trigger corresponding handler * -receive fail dialog -send -send success dialog -send fail dialog -Other * dialogs - - DIALOG_RECEIVE_ONGOING will transition to * DIALOG_RECEIVE_COMPLETE_SUCCESS or DIALOG_RECEIVE_COMPLETE_FAIL * DIALOG_SEND_ONGOING will transition to DIALOG_SEND_COMPLETE_SUCCESS or * DIALOG_SEND_COMPLETE_FAIL */ public class BluetoothOppTransferActivity extends AlertActivity implements DialogInterface.OnClickListener { private static final String TAG = "BluetoothOppTransferActivity"; private static final boolean D = Constants.DEBUG; private static final boolean V = Constants.VERBOSE; private Uri mUri; // ongoing transfer-0 complete transfer-1 boolean mIsComplete; private BluetoothOppTransferInfo mTransInfo; private ProgressBar mProgressTransfer; private TextView mPercentView; private AlertController.AlertParams mPara; private View mView = null; private TextView mLine1View, mLine2View, mLine3View, mLine5View; private int mWhichDialog; private BluetoothAdapter mAdapter; // Dialogs definition: // Receive progress dialog public static final int DIALOG_RECEIVE_ONGOING = 0; // Receive complete and success dialog public static final int DIALOG_RECEIVE_COMPLETE_SUCCESS = 1; // Receive complete and fail dialog: will display some fail reason public static final int DIALOG_RECEIVE_COMPLETE_FAIL = 2; // Send progress dialog public static final int DIALOG_SEND_ONGOING = 3; // Send complete and success dialog public static final int DIALOG_SEND_COMPLETE_SUCCESS = 4; // Send complete and fail dialog: will let user retry public static final int DIALOG_SEND_COMPLETE_FAIL = 5; /** Observer to get notified when the content observer's data changes */ private BluetoothTransferContentObserver mObserver; // do not update button during activity creating, only update when db // changes after activity created private boolean mNeedUpdateButton = false; private class BluetoothTransferContentObserver extends ContentObserver { public BluetoothTransferContentObserver() { super(new Handler()); } @Override public void onChange(boolean selfChange) { if (V) Log.v(TAG, "received db changes."); mNeedUpdateButton = true; updateProgressbar(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = getIntent(); mUri = intent.getData(); mTransInfo = new BluetoothOppTransferInfo(); mTransInfo = BluetoothOppUtility.queryRecord(this, mUri); if (mTransInfo == null) { if (V) Log.e(TAG, "Error: Can not get data from db"); finish(); return; } mIsComplete = BluetoothShare.isStatusCompleted(mTransInfo.mStatus); displayWhichDialog(); // update progress bar for ongoing transfer if (!mIsComplete) { mObserver = new BluetoothTransferContentObserver(); getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true, mObserver); } if (mWhichDialog != DIALOG_SEND_ONGOING && mWhichDialog != DIALOG_RECEIVE_ONGOING) { // set this record to INVISIBLE BluetoothOppUtility.updateVisibilityToHidden(this, mUri); } mAdapter = BluetoothAdapter.getDefaultAdapter(); // Set up the "dialog" setUpDialog(); } @Override protected void onDestroy() { if (D) Log.d(TAG, "onDestroy()"); if (mObserver != null) { getContentResolver().unregisterContentObserver(mObserver); } super.onDestroy(); } private void displayWhichDialog() { int direction = mTransInfo.mDirection; boolean isSuccess = BluetoothShare.isStatusSuccess(mTransInfo.mStatus); boolean isComplete = BluetoothShare.isStatusCompleted(mTransInfo.mStatus); if (direction == BluetoothShare.DIRECTION_INBOUND) { if (isComplete == true) { if (isSuccess == true) { // should not go here mWhichDialog = DIALOG_RECEIVE_COMPLETE_SUCCESS; } else if (isSuccess == false) { mWhichDialog = DIALOG_RECEIVE_COMPLETE_FAIL; } } else if (isComplete == false) { mWhichDialog = DIALOG_RECEIVE_ONGOING; } } else if (direction == BluetoothShare.DIRECTION_OUTBOUND) { if (isComplete == true) { if (isSuccess == true) { mWhichDialog = DIALOG_SEND_COMPLETE_SUCCESS; } else if (isSuccess == false) { mWhichDialog = DIALOG_SEND_COMPLETE_FAIL; } } else if (isComplete == false) { mWhichDialog = DIALOG_SEND_ONGOING; } } if (V) Log.v(TAG, " WhichDialog/dir/isComplete/failOrSuccess" + mWhichDialog + direction + isComplete + isSuccess); } private void setUpDialog() { // final AlertController.AlertParams p = mAlertParams; mPara = mAlertParams; mPara.mIconId = android.R.drawable.ic_dialog_info; mPara.mTitle = getString(R.string.download_title); if ((mWhichDialog == DIALOG_RECEIVE_ONGOING) || (mWhichDialog == DIALOG_SEND_ONGOING)) { mPara.mPositiveButtonText = getString(R.string.download_ok); mPara.mPositiveButtonListener = this; mPara.mNegativeButtonText = getString(R.string.download_cancel); mPara.mNegativeButtonListener = this; } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) { mPara.mPositiveButtonText = getString(R.string.download_succ_ok); mPara.mPositiveButtonListener = this; } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) { mPara.mIconId = android.R.drawable.ic_dialog_alert; mPara.mPositiveButtonText = getString(R.string.download_fail_ok); mPara.mPositiveButtonListener = this; } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) { mPara.mPositiveButtonText = getString(R.string.upload_succ_ok); mPara.mPositiveButtonListener = this; } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) { mPara.mIconId = android.R.drawable.ic_dialog_alert; mPara.mPositiveButtonText = getString(R.string.upload_fail_ok); mPara.mPositiveButtonListener = this; mPara.mNegativeButtonText = getString(R.string.upload_fail_cancel); mPara.mNegativeButtonListener = this; } mPara.mView = createView(); setupAlert(); } private View createView() { mView = getLayoutInflater().inflate(R.layout.file_transfer, null); mProgressTransfer = (ProgressBar)mView.findViewById(R.id.progress_transfer); mPercentView = (TextView)mView.findViewById(R.id.progress_percent); customizeViewContent(); // no need update button when activity creating mNeedUpdateButton = false; updateProgressbar(); return mView; } /** * customize the content of view */ private void customizeViewContent() { String tmp; if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) { mLine1View = (TextView)mView.findViewById(R.id.line1_view); tmp = getString(R.string.download_line1, mTransInfo.mDeviceName); mLine1View.setText(tmp); mLine2View = (TextView)mView.findViewById(R.id.line2_view); tmp = getString(R.string.download_line2, mTransInfo.mFileName); mLine2View.setText(tmp); mLine3View = (TextView)mView.findViewById(R.id.line3_view); tmp = getString(R.string.download_line3, Formatter.formatFileSize(this, mTransInfo.mTotalBytes)); mLine3View.setText(tmp); mLine5View = (TextView)mView.findViewById(R.id.line5_view); if (mWhichDialog == DIALOG_RECEIVE_ONGOING) { tmp = getString(R.string.download_line5); } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) { tmp = getString(R.string.download_succ_line5); } mLine5View.setText(tmp); } else if (mWhichDialog == DIALOG_SEND_ONGOING || mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) { mLine1View = (TextView)mView.findViewById(R.id.line1_view); tmp = getString(R.string.upload_line1, mTransInfo.mDeviceName); mLine1View.setText(tmp); mLine2View = (TextView)mView.findViewById(R.id.line2_view); tmp = getString(R.string.download_line2, mTransInfo.mFileName); mLine2View.setText(tmp); mLine3View = (TextView)mView.findViewById(R.id.line3_view); tmp = getString(R.string.upload_line3, mTransInfo.mFileType, Formatter.formatFileSize( this, mTransInfo.mTotalBytes)); mLine3View.setText(tmp); mLine5View = (TextView)mView.findViewById(R.id.line5_view); if (mWhichDialog == DIALOG_SEND_ONGOING) { tmp = getString(R.string.upload_line5); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) { tmp = getString(R.string.upload_succ_line5); } mLine5View.setText(tmp); } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) { if (mTransInfo.mStatus == BluetoothShare.STATUS_ERROR_SDCARD_FULL) { mLine1View = (TextView)mView.findViewById(R.id.line1_view); tmp = getString(R.string.bt_sm_2_1, mTransInfo.mDeviceName); mLine1View.setText(tmp); mLine2View = (TextView)mView.findViewById(R.id.line2_view); tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName); mLine2View.setText(tmp); mLine3View = (TextView)mView.findViewById(R.id.line3_view); tmp = getString(R.string.bt_sm_2_2, Formatter.formatFileSize(this, mTransInfo.mTotalBytes)); mLine3View.setText(tmp); } else { mLine1View = (TextView)mView.findViewById(R.id.line1_view); tmp = getString(R.string.download_fail_line1); mLine1View.setText(tmp); mLine2View = (TextView)mView.findViewById(R.id.line2_view); tmp = getString(R.string.download_fail_line2, mTransInfo.mFileName); mLine2View.setText(tmp); mLine3View = (TextView)mView.findViewById(R.id.line3_view); tmp = getString(R.string.download_fail_line3, BluetoothOppUtility .getStatusDescription(this, mTransInfo.mStatus, mTransInfo.mDeviceName)); mLine3View.setText(tmp); } mLine5View = (TextView)mView.findViewById(R.id.line5_view); mLine5View.setVisibility(View.GONE); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) { mLine1View = (TextView)mView.findViewById(R.id.line1_view); tmp = getString(R.string.upload_fail_line1, mTransInfo.mDeviceName); mLine1View.setText(tmp); mLine2View = (TextView)mView.findViewById(R.id.line2_view); tmp = getString(R.string.upload_fail_line1_2, mTransInfo.mFileName); mLine2View.setText(tmp); mLine3View = (TextView)mView.findViewById(R.id.line3_view); tmp = getString(R.string.download_fail_line3, BluetoothOppUtility.getStatusDescription( this, mTransInfo.mStatus, mTransInfo.mDeviceName)); mLine3View.setText(tmp); mLine5View = (TextView)mView.findViewById(R.id.line5_view); mLine5View.setVisibility(View.GONE); } if (BluetoothShare.isStatusError(mTransInfo.mStatus)) { mProgressTransfer.setVisibility(View.GONE); mPercentView.setVisibility(View.GONE); } } public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_POSITIVE: if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) { // "Open" - open receive file BluetoothOppUtility.openReceivedFile(this, mTransInfo.mFileName, mTransInfo.mFileType, mTransInfo.mTimeStamp, mUri); // make current transfer "hidden" BluetoothOppUtility.updateVisibilityToHidden(this, mUri); // clear correspondent notification item ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)) .cancel(mTransInfo.mID); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) { // "try again" // make current transfer "hidden" BluetoothOppUtility.updateVisibilityToHidden(this, mUri); // clear correspondent notification item ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)) .cancel(mTransInfo.mID); // retry the failed transfer BluetoothOppUtility.retryTransfer(this, mTransInfo); BluetoothDevice remoteDevice = mAdapter.getRemoteDevice(mTransInfo.mDestAddr); // Display toast message Toast.makeText( this, this.getString(R.string.bt_toast_4, BluetoothOppManager.getInstance( this).getDeviceName(remoteDevice)), Toast.LENGTH_SHORT) .show(); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) { BluetoothOppUtility.updateVisibilityToHidden(this, mUri); ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)) .cancel(mTransInfo.mID); } break; case DialogInterface.BUTTON_NEGATIVE: if (mWhichDialog == DIALOG_RECEIVE_ONGOING || mWhichDialog == DIALOG_SEND_ONGOING) { // "Stop" button this.getContentResolver().delete(mUri, null, null); String msg = ""; if (mWhichDialog == DIALOG_RECEIVE_ONGOING) { msg = getString(R.string.bt_toast_3, mTransInfo.mDeviceName); } else if (mWhichDialog == DIALOG_SEND_ONGOING) { msg = getString(R.string.bt_toast_6, mTransInfo.mDeviceName); } Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); ((NotificationManager)getSystemService(NOTIFICATION_SERVICE)) .cancel(mTransInfo.mID); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) { BluetoothOppUtility.updateVisibilityToHidden(this, mUri); } break; } finish(); } /** * Update progress bar per data got from content provider */ private void updateProgressbar() { mTransInfo = BluetoothOppUtility.queryRecord(this, mUri); if (mTransInfo == null) { if (V) Log.e(TAG, "Error: Can not get data from db"); return; } if (mTransInfo.mTotalBytes == 0) { // if Max and progress both equal 0, the progress display 100%. // Below is to fix it. mProgressTransfer.setMax(100); } else { mProgressTransfer.setMax(mTransInfo.mTotalBytes); } mProgressTransfer.setProgress(mTransInfo.mCurrentBytes); mPercentView.setText(BluetoothOppUtility.formatProgressText(mTransInfo.mTotalBytes, mTransInfo.mCurrentBytes)); // Handle the case when DIALOG_RECEIVE_ONGOING evolve to // DIALOG_RECEIVE_COMPLETE_SUCCESS/DIALOG_RECEIVE_COMPLETE_FAIL // Handle the case when DIALOG_SEND_ONGOING evolve to // DIALOG_SEND_COMPLETE_SUCCESS/DIALOG_SEND_COMPLETE_FAIL if (!mIsComplete && BluetoothShare.isStatusCompleted(mTransInfo.mStatus) && mNeedUpdateButton) { displayWhichDialog(); updateButton(); customizeViewContent(); } } /** * Update button when one transfer goto complete from ongoing */ private void updateButton() { if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) { mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText( getString(R.string.download_succ_ok)); } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) { mAlert.setIcon(android.R.drawable.ic_dialog_alert); mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText( getString(R.string.download_fail_ok)); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) { mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE); mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText( getString(R.string.upload_succ_ok)); } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) { mAlert.setIcon(android.R.drawable.ic_dialog_alert); mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText( getString(R.string.upload_fail_ok)); mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setText( getString(R.string.upload_fail_cancel)); } } }