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