Home | History | Annotate | Download | only in beam
      1 package com.android.nfc.beam;
      2 
      3 import com.android.nfc.R;
      4 
      5 import android.app.Service;
      6 import android.bluetooth.BluetoothAdapter;
      7 import android.content.BroadcastReceiver;
      8 import android.content.Context;
      9 import android.content.Intent;
     10 import android.content.IntentFilter;
     11 import android.media.AudioManager;
     12 import android.media.SoundPool;
     13 import android.os.Handler;
     14 import android.os.IBinder;
     15 import android.os.Message;
     16 import android.os.Messenger;
     17 import android.os.RemoteException;
     18 import android.util.Log;
     19 
     20 
     21 /**
     22  * @hide
     23  */
     24 public class BeamReceiveService extends Service implements BeamTransferManager.Callback {
     25     private static String TAG = "BeamReceiveService";
     26     private static boolean DBG = true;
     27 
     28     public static final String EXTRA_BEAM_TRANSFER_RECORD
     29             = "com.android.nfc.beam.EXTRA_BEAM_TRANSFER_RECORD";
     30     public static final String EXTRA_BEAM_COMPLETE_CALLBACK
     31             = "com.android.nfc.beam.TRANSFER_COMPLETE_CALLBACK";
     32 
     33     private BeamStatusReceiver mBeamStatusReceiver;
     34     private boolean mBluetoothEnabledByNfc;
     35     private int mStartId;
     36     private SoundPool mSoundPool;
     37     private int mSuccessSound;
     38     private BeamTransferManager mTransferManager;
     39     private Messenger mCompleteCallback;
     40 
     41     private final BluetoothAdapter mBluetoothAdapter;
     42     private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() {
     43         @Override
     44         public void onReceive(Context context, Intent intent) {
     45             String action = intent.getAction();
     46             if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
     47                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
     48                         BluetoothAdapter.ERROR);
     49                 if (state == BluetoothAdapter.STATE_OFF) {
     50                     mBluetoothEnabledByNfc = false;
     51                 }
     52             }
     53         }
     54     };
     55 
     56     public BeamReceiveService() {
     57         mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
     58     }
     59 
     60     @Override
     61     public int onStartCommand(Intent intent, int flags, int startId) {
     62         mStartId = startId;
     63 
     64         BeamTransferRecord transferRecord;
     65         if (intent == null ||
     66                 (transferRecord = intent.getParcelableExtra(EXTRA_BEAM_TRANSFER_RECORD)) == null) {
     67             if (DBG) Log.e(TAG, "No transfer record provided. Stopping.");
     68             stopSelf(startId);
     69             return START_NOT_STICKY;
     70         }
     71 
     72         mCompleteCallback = intent.getParcelableExtra(EXTRA_BEAM_COMPLETE_CALLBACK);
     73 
     74         if (prepareToReceive(transferRecord)) {
     75             if (DBG) Log.i(TAG, "Ready for incoming Beam transfer");
     76             return START_STICKY;
     77         } else {
     78             invokeCompleteCallback();
     79             stopSelf(startId);
     80             return START_NOT_STICKY;
     81         }
     82     }
     83 
     84     // TODO: figure out a way to not duplicate this code
     85     @Override
     86     public void onCreate() {
     87         super.onCreate();
     88 
     89         mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
     90         mSuccessSound = mSoundPool.load(this, R.raw.end, 1);
     91 
     92         // register BT state receiver
     93         IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
     94         registerReceiver(mBluetoothStateReceiver, filter);
     95     }
     96 
     97     @Override
     98     public void onDestroy() {
     99         super.onDestroy();
    100         if (mSoundPool != null) {
    101             mSoundPool.release();
    102         }
    103 
    104         if (mBeamStatusReceiver != null) {
    105             unregisterReceiver(mBeamStatusReceiver);
    106         }
    107         unregisterReceiver(mBluetoothStateReceiver);
    108     }
    109 
    110     boolean prepareToReceive(BeamTransferRecord transferRecord) {
    111         if (mTransferManager != null) {
    112             return false;
    113         }
    114 
    115         if (transferRecord.dataLinkType != BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
    116             // only support BT
    117             return false;
    118         }
    119 
    120         if (!mBluetoothAdapter.isEnabled()) {
    121             if (!mBluetoothAdapter.enableNoAutoConnect()) {
    122                 Log.e(TAG, "Error enabling Bluetooth.");
    123                 return false;
    124             }
    125             mBluetoothEnabledByNfc = true;
    126             if (DBG) Log.d(TAG, "Queueing out transfer "
    127                     + Integer.toString(transferRecord.id));
    128         }
    129 
    130         mTransferManager = new BeamTransferManager(this, this, transferRecord, true);
    131 
    132         // register Beam status receiver
    133         mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager);
    134         registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(),
    135                 BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler());
    136 
    137         mTransferManager.start();
    138         mTransferManager.updateNotification();
    139         return true;
    140     }
    141 
    142     private void invokeCompleteCallback() {
    143         if (mCompleteCallback != null) {
    144             try {
    145                 mCompleteCallback.send(Message.obtain(null, BeamManager.MSG_BEAM_COMPLETE));
    146             } catch (RemoteException e) {
    147                 Log.e(TAG, "failed to invoke Beam complete callback", e);
    148             }
    149         }
    150     }
    151 
    152     @Override
    153     public void onTransferComplete(BeamTransferManager transfer, boolean success) {
    154         // Play success sound
    155         if (success) {
    156             mSoundPool.play(mSuccessSound, 1.0f, 1.0f, 0, 0, 1.0f);
    157         } else {
    158             if (DBG) Log.d(TAG, "Transfer failed, final state: " +
    159                     Integer.toString(transfer.mState));
    160         }
    161 
    162         if (mBluetoothEnabledByNfc) {
    163             mBluetoothEnabledByNfc = false;
    164             mBluetoothAdapter.disable();
    165         }
    166 
    167         invokeCompleteCallback();
    168         stopSelf(mStartId);
    169     }
    170 
    171     @Override
    172     public IBinder onBind(Intent intent) {
    173         return null;
    174     }
    175 }
    176