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