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
17package com.android.nfc.handover;
18
19import android.bluetooth.BluetoothDevice;
20import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
23import android.net.Uri;
24import android.os.Handler;
25import android.os.Message;
26import android.os.SystemClock;
27import android.os.UserHandle;
28import android.util.Log;
29import android.webkit.MimeTypeMap;
30import java.util.ArrayList;
31import java.util.Arrays;
32
33public class BluetoothOppHandover implements Handler.Callback {
34    static final String TAG = "BluetoothOppHandover";
35    static final boolean DBG = true;
36
37    static final int STATE_INIT = 0;
38    static final int STATE_TURNING_ON = 1;
39    static final int STATE_WAITING = 2; // Need to wait for remote side turning on BT
40    static final int STATE_COMPLETE = 3;
41
42    static final int MSG_START_SEND = 0;
43
44    static final int REMOTE_BT_ENABLE_DELAY_MS = 5000;
45
46    static final String ACTION_HANDOVER_SEND =
47            "android.btopp.intent.action.HANDOVER_SEND";
48
49    static final String ACTION_HANDOVER_SEND_MULTIPLE =
50            "android.btopp.intent.action.HANDOVER_SEND_MULTIPLE";
51
52    final Context mContext;
53    final BluetoothDevice mDevice;
54
55    final Uri[] mUris;
56    final boolean mRemoteActivating;
57    final Handler mHandler;
58    final Long mCreateTime;
59
60    int mState;
61
62    public BluetoothOppHandover(Context context, BluetoothDevice device, Uri[] uris,
63            boolean remoteActivating) {
64        mContext = context;
65        mDevice = device;
66        mUris = uris;
67        mRemoteActivating = remoteActivating;
68        mCreateTime = SystemClock.elapsedRealtime();
69
70        mHandler = new Handler(context.getMainLooper(),this);
71        mState = STATE_INIT;
72    }
73
74    public static String getMimeTypeForUri(Context context, Uri uri)  {
75        if (uri.getScheme() == null) return null;
76
77        if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
78            ContentResolver cr = context.getContentResolver();
79            return cr.getType(uri);
80        } else if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
81            String extension = MimeTypeMap.getFileExtensionFromUrl(uri.getPath()).toLowerCase();
82            if (extension != null) {
83                return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
84            } else {
85                return null;
86            }
87        } else {
88            Log.d(TAG, "Could not determine mime type for Uri " + uri);
89            return null;
90        }
91    }
92
93    /**
94     * Main entry point. This method is usually called after construction,
95     * to begin the BT sequence. Must be called on Main thread.
96     */
97    public void start() {
98        if (mRemoteActivating) {
99            Long timeElapsed = SystemClock.elapsedRealtime() - mCreateTime;
100            if (timeElapsed < REMOTE_BT_ENABLE_DELAY_MS) {
101                mHandler.sendEmptyMessageDelayed(MSG_START_SEND,
102                        REMOTE_BT_ENABLE_DELAY_MS - timeElapsed);
103            } else {
104                // Already waited long enough for BT to come up
105                // - start send.
106                sendIntent();
107            }
108        } else {
109            // Remote BT enabled already, start send immediately
110            sendIntent();
111        }
112    }
113
114    void complete() {
115        mState = STATE_COMPLETE;
116    }
117
118    void sendIntent() {
119        Intent intent = new Intent();
120        intent.setPackage("com.android.bluetooth");
121        String mimeType = getMimeTypeForUri(mContext, mUris[0]);
122        intent.setType(mimeType);
123        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
124        if (mUris.length == 1) {
125            intent.setAction(ACTION_HANDOVER_SEND);
126            intent.putExtra(Intent.EXTRA_STREAM, mUris[0]);
127        } else {
128            ArrayList<Uri> uris = new ArrayList<Uri>(Arrays.asList(mUris));
129            intent.setAction(ACTION_HANDOVER_SEND_MULTIPLE);
130            intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
131        }
132        if (DBG) Log.d(TAG, "Handing off outging transfer to BT");
133        mContext.sendBroadcast(intent);
134
135        complete();
136    }
137
138
139    @Override
140    public boolean handleMessage(Message msg) {
141        if (msg.what == MSG_START_SEND) {
142            sendIntent();
143            return true;
144        }
145        return false;
146    }
147}
148