1b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales/*
2b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* Copyright (C) 2008 The Android Open Source Project
3b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales*
4b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* Licensed under the Apache License, Version 2.0 (the "License");
5b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* you may not use this file except in compliance with the License.
6b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* You may obtain a copy of the License at
7b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales*
8b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales*      http://www.apache.org/licenses/LICENSE-2.0
9b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales*
10b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* Unless required by applicable law or agreed to in writing, software
11b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* distributed under the License is distributed on an "AS IS" BASIS,
12b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* See the License for the specific language governing permissions and
14b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales* limitations under the License.
15b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales*/
16b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralespackage com.android.nfc.beam;
17b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
18d822fd4358912161f637968610588e71493bbcd2Atsushi Sugaimport com.android.nfc.NfcService;
19073f0981e3920c085a57ff46f7f41bf329071c89Akinobu Nakashimaimport com.android.nfc.R;
20b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.HandoverDataParser;
21b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
22b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.bluetooth.BluetoothDevice;
23b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.content.Context;
24b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.content.Intent;
25b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.net.Uri;
26b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.os.Handler;
27b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.os.Looper;
28b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.os.Message;
29b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.os.Messenger;
30b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.os.UserHandle;
31b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.util.Log;
32b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
33b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales/**
34b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * Manager for starting and stopping Beam transfers. Prevents more than one transfer from
35b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales * happening at a time.
36b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales */
37b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralespublic class BeamManager implements Handler.Callback {
38b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private static final String TAG = "BeamManager";
39b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private static final boolean DBG = false;
40b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
41b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private static final String ACTION_WHITELIST_DEVICE =
42b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            "android.btopp.intent.action.WHITELIST_DEVICE";
43b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public static final int MSG_BEAM_COMPLETE = 0;
44b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
45b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private final Object mLock;
46b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
47b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private boolean mBeamInProgress;
48b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private final Handler mCallback;
49b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
50d822fd4358912161f637968610588e71493bbcd2Atsushi Suga    private NfcService mNfcService;
51d822fd4358912161f637968610588e71493bbcd2Atsushi Suga
52b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private static final class Singleton {
53b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        public static final BeamManager INSTANCE = new BeamManager();
54b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
55b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
56b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private BeamManager() {
57b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mLock = new Object();
58b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mBeamInProgress = false;
59b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mCallback = new Handler(Looper.getMainLooper(), this);
60d822fd4358912161f637968610588e71493bbcd2Atsushi Suga        mNfcService = NfcService.getInstance();
61b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
62b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
63b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public static BeamManager getInstance() {
64b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        return Singleton.INSTANCE;
65b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
66b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
67b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public boolean isBeamInProgress() {
68b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        synchronized (mLock) {
69b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            return mBeamInProgress;
70b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        }
71b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
72b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
73b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public boolean startBeamReceive(Context context,
74b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                                 HandoverDataParser.BluetoothHandoverData handoverData) {
75b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        synchronized (mLock) {
76b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            if (mBeamInProgress) {
77b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                return false;
78b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            } else {
79b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                mBeamInProgress = true;
80b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            }
81b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        }
82b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
83b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        BeamTransferRecord transferRecord =
84b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                BeamTransferRecord.forBluetoothDevice(
85b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                        handoverData.device, handoverData.carrierActivating, null);
86b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
87b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        Intent receiveIntent = new Intent(context.getApplicationContext(),
88b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                BeamReceiveService.class);
89b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
90b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        receiveIntent.putExtra(BeamReceiveService.EXTRA_BEAM_COMPLETE_CALLBACK,
91b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                new Messenger(mCallback));
92b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        whitelistOppDevice(context, handoverData.device);
93b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        context.startServiceAsUser(receiveIntent, UserHandle.CURRENT);
94b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        return true;
95b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
96b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
97b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public boolean startBeamSend(Context context,
98b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                               HandoverDataParser.BluetoothHandoverData outgoingHandoverData,
99b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                               Uri[] uris, UserHandle userHandle) {
100b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        synchronized (mLock) {
101b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            if (mBeamInProgress) {
102b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                return false;
103b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            } else {
104b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                mBeamInProgress = true;
105b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            }
106b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        }
107b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
108b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        BeamTransferRecord transferRecord = BeamTransferRecord.forBluetoothDevice(
109b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                outgoingHandoverData.device, outgoingHandoverData.carrierActivating,
110b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                uris);
111b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        Intent sendIntent = new Intent(context.getApplicationContext(),
112b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                BeamSendService.class);
113b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        sendIntent.putExtra(BeamSendService.EXTRA_BEAM_TRANSFER_RECORD, transferRecord);
114b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        sendIntent.putExtra(BeamSendService.EXTRA_BEAM_COMPLETE_CALLBACK,
115b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                new Messenger(mCallback));
116b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        context.startServiceAsUser(sendIntent, userHandle);
117b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        return true;
118b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
119b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
120b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    @Override
121b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    public boolean handleMessage(Message msg) {
122b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        if (msg.what == MSG_BEAM_COMPLETE) {
123b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            synchronized (mLock) {
124b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales                mBeamInProgress = false;
125b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            }
126d822fd4358912161f637968610588e71493bbcd2Atsushi Suga
127d822fd4358912161f637968610588e71493bbcd2Atsushi Suga            boolean success = msg.arg1 == 1;
128d822fd4358912161f637968610588e71493bbcd2Atsushi Suga            if (success) {
129d822fd4358912161f637968610588e71493bbcd2Atsushi Suga                mNfcService.playSound(NfcService.SOUND_END);
130d822fd4358912161f637968610588e71493bbcd2Atsushi Suga            }
131b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales            return true;
132b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        }
133b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        return false;
134b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
135b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
136b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    void whitelistOppDevice(Context context, BluetoothDevice device) {
137b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
138b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        Intent intent = new Intent(ACTION_WHITELIST_DEVICE);
139073f0981e3920c085a57ff46f7f41bf329071c89Akinobu Nakashima        intent.setPackage(context.getString(R.string.bluetooth_package));
140b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
141b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        context.sendBroadcastAsUser(intent, UserHandle.CURRENT);
142b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    }
143b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales
144b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales}
145