Home | History | Annotate | Download | only in opp
      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.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 
    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      */
    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 
    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      */
    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         if (mTransInfo.mTotalBytes == 0) {
    427             // if Max and progress both equal 0, the progress display 100%.
    428             // Below is to fix it.
    429             mProgressTransfer.setMax(100);
    430         } else {
    431             mProgressTransfer.setMax(mTransInfo.mTotalBytes);
    432         }
    433 
    434         mProgressTransfer.setProgress(mTransInfo.mCurrentBytes);
    435 
    436         mPercentView.setText(BluetoothOppUtility.formatProgressText(mTransInfo.mTotalBytes,
    437                 mTransInfo.mCurrentBytes));
    438 
    439         // Handle the case when DIALOG_RECEIVE_ONGOING evolve to
    440         // DIALOG_RECEIVE_COMPLETE_SUCCESS/DIALOG_RECEIVE_COMPLETE_FAIL
    441         // Handle the case when DIALOG_SEND_ONGOING evolve to
    442         // DIALOG_SEND_COMPLETE_SUCCESS/DIALOG_SEND_COMPLETE_FAIL
    443         if (!mIsComplete && BluetoothShare.isStatusCompleted(mTransInfo.mStatus)
    444                 && mNeedUpdateButton) {
    445             displayWhichDialog();
    446             updateButton();
    447             customizeViewContent();
    448         }
    449     }
    450 
    451     /**
    452      * Update button when one transfer goto complete from ongoing
    453      */
    454     private void updateButton() {
    455         if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS) {
    456             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
    457             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
    458                     getString(R.string.download_succ_ok));
    459         } else if (mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL) {
    460             mAlert.setIcon(mAlert.getIconAttributeResId(android.R.attr.alertDialogIcon));
    461             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
    462             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
    463                     getString(R.string.download_fail_ok));
    464         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_SUCCESS) {
    465             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setVisibility(View.GONE);
    466             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
    467                     getString(R.string.upload_succ_ok));
    468         } else if (mWhichDialog == DIALOG_SEND_COMPLETE_FAIL) {
    469             mAlert.setIcon(mAlert.getIconAttributeResId(android.R.attr.alertDialogIcon));
    470             mAlert.getButton(DialogInterface.BUTTON_POSITIVE).setText(
    471                     getString(R.string.upload_fail_ok));
    472             mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).setText(
    473                     getString(R.string.upload_fail_cancel));
    474         }
    475     }
    476 }
    477