• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                     Context.RECEIVER_EXPORTED);
112 
113             if (transferRecord.dataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
114                 if (mBluetoothAdapter.isEnabled()) {
115                     // Start the transfer
116                     mTransferManager.start();
117                 } else {
118                     if (!mBluetoothAdapter.enableNoAutoConnect()) {
119                         Log.e(TAG, "Error enabling Bluetooth.");
120                         mTransferManager = null;
121                         return false;
122                     }
123                     mBluetoothEnabledByNfc = true;
124                     if (DBG) Log.d(TAG, "Queueing out transfer "
125                             + Integer.toString(transferRecord.id));
126                 }
127             }
128             return true;
129         }
130 
131         return false;
132     }
133 
createBeamTransferManager(BeamTransferRecord transferRecord)134     boolean createBeamTransferManager(BeamTransferRecord transferRecord) {
135         if (mTransferManager != null) {
136             return false;
137         }
138 
139         if (transferRecord.dataLinkType != BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
140             // only support BT
141             return false;
142         }
143 
144         mTransferManager = new BeamTransferManager(this, this, transferRecord, false);
145         mTransferManager.updateNotification();
146         return true;
147     }
148 
handleBluetoothStateChanged(Intent intent)149     private void handleBluetoothStateChanged(Intent intent) {
150         int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
151                 BluetoothAdapter.ERROR);
152         if (state == BluetoothAdapter.STATE_ON) {
153             if (mTransferManager != null &&
154                     mTransferManager.mDataLinkType == BeamTransferRecord.DATA_LINK_TYPE_BLUETOOTH) {
155                 mTransferManager.start();
156             }
157         }
158     }
159 
invokeCompleteCallback(boolean success)160     private void invokeCompleteCallback(boolean success) {
161         if (mCompleteCallback != null) {
162             try {
163                 Message msg = Message.obtain(null, BeamManager.MSG_BEAM_COMPLETE);
164                 msg.arg1 = success ? 1 : 0;
165                 mCompleteCallback.send(msg);
166             } catch (RemoteException e) {
167                 Log.e(TAG, "failed to invoke Beam complete callback", e);
168             }
169         }
170     }
171 
172     @Override
onTransferComplete(BeamTransferManager transfer, boolean success)173     public void onTransferComplete(BeamTransferManager transfer, boolean success) {
174         // Play success sound
175         if (!success) {
176             if (DBG) Log.d(TAG, "Transfer failed, final state: " +
177                     Integer.toString(transfer.mState));
178         }
179 
180         if (mBluetoothEnabledByNfc) {
181             mBluetoothEnabledByNfc = false;
182             mBluetoothAdapter.disable();
183         }
184 
185         invokeCompleteCallback(success);
186         stopSelf(mStartId);
187     }
188 
189     @Override
onBind(Intent intent)190     public IBinder onBind(Intent intent) {
191         return null;
192     }
193 }
194