• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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 com.android.nfc.R;
20 
21 import android.bluetooth.BluetoothDevice;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.net.Uri;
25 import android.os.Handler;
26 import android.os.Message;
27 import android.os.SystemClock;
28 import android.util.Log;
29 
30 import java.util.ArrayList;
31 
32 public class BluetoothOppHandover implements Handler.Callback {
33     static final String TAG = "BluetoothOppHandover";
34     static final boolean DBG = true;
35 
36     static final int STATE_INIT = 0;
37     static final int STATE_TURNING_ON = 1;
38     static final int STATE_WAITING = 2; // Need to wait for remote side turning on BT
39     static final int STATE_COMPLETE = 3;
40 
41     static final int MSG_START_SEND = 0;
42 
43     static final int REMOTE_BT_ENABLE_DELAY_MS = 5000;
44 
45     static final String ACTION_HANDOVER_SEND =
46             "android.nfc.handover.intent.action.HANDOVER_SEND";
47 
48     static final String ACTION_HANDOVER_SEND_MULTIPLE =
49             "android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE";
50 
51     final Context mContext;
52     final BluetoothDevice mDevice;
53 
54     final ArrayList<Uri> mUris;
55     final boolean mRemoteActivating;
56     final Handler mHandler;
57     final Long mCreateTime;
58 
59     int mState;
60 
BluetoothOppHandover(Context context, BluetoothDevice device, ArrayList<Uri> uris, boolean remoteActivating)61     public BluetoothOppHandover(Context context, BluetoothDevice device, ArrayList<Uri> uris,
62             boolean remoteActivating) {
63         mContext = context;
64         mDevice = device;
65         mUris = uris;
66         mRemoteActivating = remoteActivating;
67         mCreateTime = SystemClock.elapsedRealtime();
68 
69         mHandler = new Handler(context.getMainLooper(), this);
70         mState = STATE_INIT;
71     }
72 
73     /**
74      * Main entry point. This method is usually called after construction,
75      * to begin the BT sequence. Must be called on Main thread.
76      */
start()77     public void start() {
78         if (mRemoteActivating) {
79             Long timeElapsed = SystemClock.elapsedRealtime() - mCreateTime;
80             if (timeElapsed < REMOTE_BT_ENABLE_DELAY_MS) {
81                 mHandler.sendEmptyMessageDelayed(MSG_START_SEND,
82                         REMOTE_BT_ENABLE_DELAY_MS - timeElapsed);
83             } else {
84                 // Already waited long enough for BT to come up
85                 // - start send.
86                 sendIntent();
87             }
88         } else {
89             // Remote BT enabled already, start send immediately
90             sendIntent();
91         }
92     }
93 
complete()94     void complete() {
95         mState = STATE_COMPLETE;
96     }
97 
sendIntent()98     void sendIntent() {
99         Intent intent = new Intent();
100         intent.setPackage(mContext.getString(R.string.bluetooth_package));
101         String mimeType = MimeTypeUtil.getMimeTypeForUri(mContext, mUris.get(0));
102         intent.setType(mimeType);
103         intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
104         for (Uri uri : mUris) {
105             // TODO we need to transfer our permission grant from NFC
106             // to the Bluetooth process. This works, but we don't have
107             // a good framework API for revoking permission yet.
108             try {
109                 mContext.grantUriPermission(mContext.getString(R.string.bluetooth_package), uri,
110                         Intent.FLAG_GRANT_READ_URI_PERMISSION);
111             } catch (SecurityException e) {
112                 Log.e(TAG, "Failed to transfer permission to Bluetooth process.");
113             }
114         }
115         if (mUris.size() == 1) {
116             intent.setAction(ACTION_HANDOVER_SEND);
117             intent.putExtra(Intent.EXTRA_STREAM, mUris.get(0));
118         } else {
119             intent.setAction(ACTION_HANDOVER_SEND_MULTIPLE);
120             intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, mUris);
121         }
122         if (DBG) Log.d(TAG, "Handing off outging transfer to BT");
123         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
124         mContext.sendBroadcast(intent);
125 
126         complete();
127     }
128 
129 
130     @Override
handleMessage(Message msg)131     public boolean handleMessage(Message msg) {
132         if (msg.what == MSG_START_SEND) {
133             sendIntent();
134             return true;
135         }
136         return false;
137     }
138 }
139