1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.nfc.beam; 18 19 import android.app.Service; 20 import android.bluetooth.BluetoothAdapter; 21 import android.content.BroadcastReceiver; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.content.IntentFilter; 25 import android.os.Handler; 26 import android.os.IBinder; 27 import android.os.Message; 28 import android.os.Messenger; 29 import android.os.RemoteException; 30 import android.util.Log; 31 32 public class BeamSendService extends Service implements BeamTransferManager.Callback { 33 private static String TAG = "BeamSendService"; 34 private static boolean DBG = true; 35 36 public static String EXTRA_BEAM_TRANSFER_RECORD 37 = "com.android.nfc.beam.EXTRA_BEAM_TRANSFER_RECORD"; 38 public static final String EXTRA_BEAM_COMPLETE_CALLBACK 39 = "com.android.nfc.beam.TRANSFER_COMPLETE_CALLBACK"; 40 41 private BeamTransferManager mTransferManager; 42 private BeamStatusReceiver mBeamStatusReceiver; 43 private boolean mBluetoothEnabledByNfc; 44 private Messenger mCompleteCallback; 45 private int mStartId; 46 47 private final BluetoothAdapter mBluetoothAdapter; 48 private final BroadcastReceiver mBluetoothStateReceiver = new BroadcastReceiver() { 49 @Override 50 public void onReceive(Context context, Intent intent) { 51 String action = intent.getAction(); 52 if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 53 handleBluetoothStateChanged(intent); 54 } 55 } 56 }; 57 BeamSendService()58 public BeamSendService() { 59 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 60 } 61 62 @Override onCreate()63 public void onCreate() { 64 super.onCreate(); 65 66 // register BT state receiver 67 IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED); 68 registerReceiver(mBluetoothStateReceiver, filter); 69 } 70 71 @Override onDestroy()72 public void onDestroy() { 73 super.onDestroy(); 74 75 if (mBeamStatusReceiver != null) { 76 unregisterReceiver(mBeamStatusReceiver); 77 } 78 unregisterReceiver(mBluetoothStateReceiver); 79 } 80 81 @Override onStartCommand(Intent intent, int flags, int startId)82 public int onStartCommand(Intent intent, int flags, int startId) { 83 mStartId = startId; 84 85 BeamTransferRecord transferRecord; 86 if (intent == null || 87 (transferRecord = intent.getParcelableExtra(EXTRA_BEAM_TRANSFER_RECORD)) == null) { 88 if (DBG) Log.e(TAG, "No transfer record provided. Stopping."); 89 stopSelf(startId); 90 return START_NOT_STICKY; 91 } 92 93 mCompleteCallback = intent.getParcelableExtra(EXTRA_BEAM_COMPLETE_CALLBACK); 94 95 if (doTransfer(transferRecord)) { 96 if (DBG) Log.i(TAG, "Starting outgoing Beam transfer"); 97 return START_STICKY; 98 } else { 99 invokeCompleteCallback(false); 100 stopSelf(startId); 101 return START_NOT_STICKY; 102 } 103 } 104 doTransfer(BeamTransferRecord transferRecord)105 boolean doTransfer(BeamTransferRecord transferRecord) { 106 if (createBeamTransferManager(transferRecord)) { 107 // register Beam status receiver 108 mBeamStatusReceiver = new BeamStatusReceiver(this, mTransferManager); 109 registerReceiver(mBeamStatusReceiver, mBeamStatusReceiver.getIntentFilter(), 110 BeamStatusReceiver.BEAM_STATUS_PERMISSION, new Handler()); 111 112 if (transferRecord.dataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) { 113 if (mBluetoothAdapter.isEnabled()) { 114 // Start the transfer 115 mTransferManager.start(); 116 } else { 117 if (!mBluetoothAdapter.enableNoAutoConnect()) { 118 Log.e(TAG, "Error enabling Bluetooth."); 119 mTransferManager = null; 120 return false; 121 } 122 mBluetoothEnabledByNfc = true; 123 if (DBG) Log.d(TAG, "Queueing out transfer " 124 + Integer.toString(transferRecord.id)); 125 } 126 } 127 return true; 128 } 129 130 return false; 131 } 132 createBeamTransferManager(BeamTransferRecord transferRecord)133 boolean createBeamTransferManager(BeamTransferRecord transferRecord) { 134 if (mTransferManager != null) { 135 return false; 136 } 137 138 if (transferRecord.dataLinkType != BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) { 139 // only support BT 140 return false; 141 } 142 143 mTransferManager = new BeamTransferManager(this, this, transferRecord, false); 144 mTransferManager.updateNotification(); 145 return true; 146 } 147 handleBluetoothStateChanged(Intent intent)148 private void handleBluetoothStateChanged(Intent intent) { 149 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 150 BluetoothAdapter.ERROR); 151 if (state == BluetoothAdapter.STATE_ON) { 152 if (mTransferManager != null && 153 mTransferManager.mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) { 154 mTransferManager.start(); 155 } 156 } 157 } 158 invokeCompleteCallback(boolean success)159 private void invokeCompleteCallback(boolean success) { 160 if (mCompleteCallback != null) { 161 try { 162 Message msg = Message.obtain(null, BeamManager.MSG_BEAM_COMPLETE); 163 msg.arg1 = success ? 1 : 0; 164 mCompleteCallback.send(msg); 165 } catch (RemoteException e) { 166 Log.e(TAG, "failed to invoke Beam complete callback", e); 167 } 168 } 169 } 170 171 @Override onTransferComplete(BeamTransferManager transfer, boolean success)172 public void onTransferComplete(BeamTransferManager transfer, boolean success) { 173 // Play success sound 174 if (!success) { 175 if (DBG) Log.d(TAG, "Transfer failed, final state: " + 176 Integer.toString(transfer.mState)); 177 } 178 179 if (mBluetoothEnabledByNfc) { 180 mBluetoothEnabledByNfc = false; 181 mBluetoothAdapter.disable(); 182 } 183 184 invokeCompleteCallback(success); 185 stopSelf(mStartId); 186 } 187 188 @Override onBind(Intent intent)189 public IBinder onBind(Intent intent) { 190 return null; 191 } 192 } 193