1/*
2* Copyright (C) 2008 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*/
16package com.android.nfc.beam;
17
18import com.android.nfc.NfcService;
19import com.android.nfc.R;
20import com.android.nfc.handover.HandoverDataParser;
21
22import android.bluetooth.BluetoothDevice;
23import android.content.Context;
24import android.content.Intent;
25import android.net.Uri;
26import android.os.Handler;
27import android.os.Looper;
28import android.os.Message;
29import android.os.Messenger;
30import android.os.UserHandle;
31import android.util.Log;
32
33/**
34 * Manager for starting and stopping Beam transfers. Prevents more than one transfer from
35 * happening at a time.
36 */
37public class BeamManager implements Handler.Callback {
38    private static final String TAG = "BeamManager";
39    private static final boolean DBG = false;
40
41    private static final String ACTION_WHITELIST_DEVICE =
42            "android.btopp.intent.action.WHITELIST_DEVICE";
43    public static final int MSG_BEAM_COMPLETE = 0;
44
45    private final Object mLock;
46
47    private boolean mBeamInProgress;
48    private final Handler mCallback;
49
50    private NfcService mNfcService;
51
52    private static final class Singleton {
53        public static final BeamManager INSTANCE = new BeamManager();
54    }
55
56    private BeamManager() {
57        mLock = new Object();
58        mBeamInProgress = false;
59        mCallback = new Handler(Looper.getMainLooper(), this);
60        mNfcService = NfcService.getInstance();
61    }
62
63    public static BeamManager getInstance() {
64        return Singleton.INSTANCE;
65    }
66
67    public boolean isBeamInProgress() {
68        synchronized (mLock) {
69            return mBeamInProgress;
70        }
71    }
72
73    public boolean startBeamReceive(Context context,
74                                 HandoverDataParser.BluetoothHandoverData handoverData) {
75        synchronized (mLock) {
76            if (mBeamInProgress) {
77                return false;
78            } else {
79                mBeamInProgress = true;
80            }
81        }
82
83        BeamTransferRecord transferRecord =
84                BeamTransferRecord.forBluetoothDevice(
85                        handoverData.device, handoverData.carrierActivating, null);
86
87        Intent receiveIntent = new Intent(context.getApplicationContext(),
88                BeamReceiveService.class);
89        receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
90        receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_COMPLETE_CALLBACK,
91                new Messenger(mCallback));
92        whitelistOppDevice(context, handoverData.device);
93        context.startServiceAsUser(receiveIntent, UserHandle.CURRENT);
94        return true;
95    }
96
97    public boolean startBeamSend(Context context,
98                               HandoverDataParser.BluetoothHandoverData outgoingHandoverData,
99                               Uri[] uris, UserHandle userHandle) {
100        synchronized (mLock) {
101            if (mBeamInProgress) {
102                return false;
103            } else {
104                mBeamInProgress = true;
105            }
106        }
107
108        BeamTransferRecord transferRecord = BeamTransferRecord.forBluetoothDevice(
109                outgoingHandoverData.device, outgoingHandoverData.carrierActivating,
110                uris);
111        Intent sendIntent = new Intent(context.getApplicationContext(),
112                BeamSendService.class);
113        sendIntent.putExtra(BeamSendService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
114        sendIntent.putExtra(BeamSendService.EXTRA_BEAM_COMPLETE_CALLBACK,
115                new Messenger(mCallback));
116        context.startServiceAsUser(sendIntent, userHandle);
117        return true;
118    }
119
120    @Override
121    public boolean handleMessage(Message msg) {
122        if (msg.what == MSG_BEAM_COMPLETE) {
123            synchronized (mLock) {
124                mBeamInProgress = false;
125            }
126
127            boolean success = msg.arg1 == 1;
128            if (success) {
129                mNfcService.playSound(NfcService.SOUND_END);
130            }
131            return true;
132        }
133        return false;
134    }
135
136    void whitelistOppDevice(Context context, BluetoothDevice device) {
137        if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
138        Intent intent = new Intent(ACTION_WHITELIST_DEVICE);
139        intent.setPackage(context.getString(R.string.bluetooth_package));
140        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
141        context.sendBroadcastAsUser(intent, UserHandle.CURRENT);
142    }
143
144}
145