13b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen/*
23b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * Copyright (C) 2012 The Android Open Source Project
33b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen *
43b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
53b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * you may not use this file except in compliance with the License.
63b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * You may obtain a copy of the License at
73b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen *
83b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
93b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen *
103b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * Unless required by applicable law or agreed to in writing, software
113b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
123b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * See the License for the specific language governing permissions and
143b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen * limitations under the License.
153b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen */
163b5a46f86f97d1624d82fa4c56ef175308e7dc65Martijn Coenen
17be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectpackage com.android.nfc.handover;
18be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
19be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.Notification;
20be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.NotificationManager;
21be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.PendingIntent;
22be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.app.Notification.Builder;
23be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.bluetooth.BluetoothDevice;
24be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.content.ContentResolver;
25be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.content.Context;
26be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.content.Intent;
27be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.media.MediaScannerConnection;
28be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.net.Uri;
29be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Environment;
30be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Handler;
31be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Looper;
32be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.Message;
33be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.SystemClock;
34be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.os.UserHandle;
35be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport android.util.Log;
36be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
37be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport com.android.nfc.R;
38be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
39be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.io.File;
40be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.text.SimpleDateFormat;
41be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.util.ArrayList;
42be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.util.Date;
43be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectimport java.util.HashMap;
44116dfa0107cdc7ab098ed95828280542bf6b0a1eThe Android Open Source Projectimport java.util.Locale;
45be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
46be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project/**
47be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * A HandoverTransfer object represents a set of files
48be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * that were received through NFC connection handover
49be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * from the same source address.
50be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project *
51be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * For Bluetooth, files are received through OPP, and
52be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * we have no knowledge how many files will be transferred
53be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * as part of a single transaction.
54be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * Hence, a transfer has a notion of being "alive": if
55be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * the last update to a transfer was within WAIT_FOR_NEXT_TRANSFER_MS
56be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * milliseconds, we consider a new file transfer from the
57be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * same source address as part of the same transfer.
58be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project * The corresponding URIs will be grouped in a single folder.
59be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project *
60be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project */
61be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Projectpublic class HandoverTransfer implements Handler.Callback,
62be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        MediaScannerConnection.OnScanCompletedListener {
63be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
64be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    interface Callback {
65be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        void onTransferComplete(HandoverTransfer transfer, boolean success);
66be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    };
67be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
68be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final String TAG = "HandoverTransfer";
69be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
70be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final Boolean DBG = true;
71be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
72be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // In the states below we still accept new file transfer
73be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_NEW = 0;
74be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_IN_PROGRESS = 1;
75be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_W4_NEXT_TRANSFER = 2;
76be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
77be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // In the states below no new files are accepted.
78be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_W4_MEDIA_SCANNER = 3;
79be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_FAILED = 4;
80be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_SUCCESS = 5;
81be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int STATE_CANCELLED = 6;
82be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
83be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int MSG_NEXT_TRANSFER_TIMER = 0;
84be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int MSG_TRANSFER_TIMEOUT = 1;
85be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
86be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // We need to receive an update within this time period
87be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // to still consider this transfer to be "alive" (ie
88be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // a reason to keep the handover transport enabled).
89be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int ALIVE_CHECK_MS = 20000;
90be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
91be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // The amount of time to wait for a new transfer
92be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // once the current one completes.
93be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final int WAIT_FOR_NEXT_TRANSFER_MS = 4000;
94be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
95be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    static final String BEAM_DIR = "beam";
96be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
97be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final boolean mIncoming;  // whether this is an incoming transfer
98be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final int mTransferId; // Unique ID of this transfer used for notifications
99be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final PendingIntent mCancelIntent;
100be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final Context mContext;
101be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final Handler mHandler;
102be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final NotificationManager mNotificationManager;
103be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final BluetoothDevice mRemoteDevice;
104be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    final Callback mCallback;
105be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
106be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    // Variables below are only accessed on the main thread
107be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    int mState;
108d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen    int mCurrentCount;
109d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen    int mSuccessCount;
110d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen    int mTotalCount;
111be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    boolean mCalledBack;
112be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    Long mLastUpdate; // Last time an event occurred for this transfer
113be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    float mProgress; // Progress in range [0..1]
114be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    ArrayList<Uri> mBtUris; // Received uris from Bluetooth OPP
115be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    ArrayList<String> mBtMimeTypes; // Mime-types received from Bluetooth OPP
116be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
117be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    ArrayList<String> mPaths; // Raw paths on the filesystem for Beam-stored files
118be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    HashMap<String, String> mMimeTypes; // Mime-types associated with each path
119be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    HashMap<String, Uri> mMediaUris; // URIs found by the media scanner for each path
120be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    int mUrisScanned;
121be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
122be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public HandoverTransfer(Context context, Callback callback,
123be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            PendingHandoverTransfer pendingTransfer) {
124be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mContext = context;
125be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mCallback = callback;
126be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mRemoteDevice = pendingTransfer.remoteDevice;
127be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mIncoming = pendingTransfer.incoming;
128be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mTransferId = pendingTransfer.id;
129d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        // For incoming transfers, count can be set later
130d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        mTotalCount = (pendingTransfer.uris != null) ? pendingTransfer.uris.length : 0;
131be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mLastUpdate = SystemClock.elapsedRealtime();
132be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mProgress = 0.0f;
133be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mState = STATE_NEW;
134be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mBtUris = new ArrayList<Uri>();
135be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mBtMimeTypes = new ArrayList<String>();
136be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mPaths = new ArrayList<String>();
137be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mMimeTypes = new HashMap<String, String>();
138be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mMediaUris = new HashMap<String, Uri>();
139d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        mCancelIntent = buildCancelIntent(mIncoming);
140be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mUrisScanned = 0;
141d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        mCurrentCount = 0;
142d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        mSuccessCount = 0;
143be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
144be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mHandler = new Handler(Looper.getMainLooper(), this);
145be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mHandler.sendEmptyMessageDelayed(MSG_TRANSFER_TIMEOUT, ALIVE_CHECK_MS);
146be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mNotificationManager = (NotificationManager) mContext.getSystemService(
147be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                Context.NOTIFICATION_SERVICE);
148be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
149be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
150be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    void whitelistOppDevice(BluetoothDevice device) {
151be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (DBG) Log.d(TAG, "Whitelisting " + device + " for BT OPP");
152be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        Intent intent = new Intent(HandoverManager.ACTION_WHITELIST_DEVICE);
153be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
154be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
155be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
156be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
157be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public void updateFileProgress(float progress) {
158be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (!isRunning()) return; // Ignore when we're no longer running
159be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
160be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mHandler.removeMessages(MSG_NEXT_TRANSFER_TIMER);
161be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
162be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        this.mProgress = progress;
163be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
164be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // We're still receiving data from this device - keep it in
165be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // the whitelist for a while longer
166be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mIncoming) whitelistOppDevice(mRemoteDevice);
167be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
168be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        updateStateAndNotification(STATE_IN_PROGRESS);
169be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
170be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
171be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public void finishTransfer(boolean success, Uri uri, String mimeType) {
172be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (!isRunning()) return; // Ignore when we're no longer running
173be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
174d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        mCurrentCount++;
175be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (success && uri != null) {
176d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            mSuccessCount++;
177be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (DBG) Log.d(TAG, "Transfer success, uri " + uri + " mimeType " + mimeType);
178d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            mProgress = 0.0f;
179be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (mimeType == null) {
180be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mimeType = BluetoothOppHandover.getMimeTypeForUri(mContext, uri);
181be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            }
182be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (mimeType != null) {
183be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mBtUris.add(uri);
184be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mBtMimeTypes.add(mimeType);
185be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            } else {
186be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                if (DBG) Log.d(TAG, "Could not get mimeType for file.");
187be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            }
188be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else {
189be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            Log.e(TAG, "Handover transfer failed");
190be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            // Do wait to see if there's another file coming.
191be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
192be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mHandler.removeMessages(MSG_NEXT_TRANSFER_TIMER);
193d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        if (mCurrentCount == mTotalCount) {
194d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            if (mIncoming) {
195d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                processFiles();
196d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            } else {
197d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                updateStateAndNotification(mSuccessCount > 0 ? STATE_SUCCESS : STATE_FAILED);
198d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            }
199d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        } else {
200d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            mHandler.sendEmptyMessageDelayed(MSG_NEXT_TRANSFER_TIMER, WAIT_FOR_NEXT_TRANSFER_MS);
201d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            updateStateAndNotification(STATE_W4_NEXT_TRANSFER);
202d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        }
203be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
204be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
205be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public boolean isRunning() {
206be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mState != STATE_NEW && mState != STATE_IN_PROGRESS && mState != STATE_W4_NEXT_TRANSFER) {
207be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return false;
208be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else {
209be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return true;
210be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
211be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
212be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
213d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen    public void setObjectCount(int objectCount) {
214d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        mTotalCount = objectCount;
215d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen    }
216d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen
217be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    void cancel() {
218be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (!isRunning()) return;
219be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
220be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // Delete all files received so far
221be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        for (Uri uri : mBtUris) {
222be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            File file = new File(uri.getPath());
223be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (file.exists()) file.delete();
224be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
225be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
226be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        updateStateAndNotification(STATE_CANCELLED);
227be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
228be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
229be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    void updateNotification() {
230be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        Builder notBuilder = new Notification.Builder(mContext);
231be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
232d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        String beamString;
233d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        if (mIncoming) {
234d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            beamString = mContext.getString(R.string.beam_progress);
235d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        } else {
236d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            beamString = mContext.getString(R.string.beam_outgoing);
237d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        }
238be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mState == STATE_NEW || mState == STATE_IN_PROGRESS ||
239be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mState == STATE_W4_NEXT_TRANSFER || mState == STATE_W4_MEDIA_SCANNER) {
240be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setAutoCancel(false);
24170fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen            notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download :
24270fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen                    android.R.drawable.stat_sys_upload);
243d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            notBuilder.setTicker(beamString);
244d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            notBuilder.setContentTitle(beamString);
245be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.addAction(R.drawable.ic_menu_cancel_holo_dark,
246be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                    mContext.getString(R.string.cancel), mCancelIntent);
247d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            float progress = 0;
248d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            if (mTotalCount > 0) {
249d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                float progressUnit = 1.0f / mTotalCount;
250d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                progress = (float) mCurrentCount * progressUnit + mProgress * progressUnit;
251d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            }
252d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            if (mTotalCount > 0 && progress > 0) {
253d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                notBuilder.setProgress(100, (int) (100 * progress), false);
254d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            } else {
255d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                notBuilder.setProgress(100, 0, true);
256d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            }
257be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else if (mState == STATE_SUCCESS) {
258be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setAutoCancel(true);
25970fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen            notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download_done :
26070fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen                    android.R.drawable.stat_sys_upload_done);
261be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setTicker(mContext.getString(R.string.beam_complete));
262be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setContentTitle(mContext.getString(R.string.beam_complete));
263be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
264d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            if (mIncoming) {
265d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                notBuilder.setContentText(mContext.getString(R.string.beam_touch_to_view));
266d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                Intent viewIntent = buildViewIntent();
267d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                PendingIntent contentIntent = PendingIntent.getActivity(
268d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                        mContext, mTransferId, viewIntent, 0, null);
269be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
270d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                notBuilder.setContentIntent(contentIntent);
271d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen            }
272be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else if (mState == STATE_FAILED) {
273be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setAutoCancel(false);
27470fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen            notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download_done :
27570fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen                    android.R.drawable.stat_sys_upload_done);
276be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setTicker(mContext.getString(R.string.beam_failed));
277be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setContentTitle(mContext.getString(R.string.beam_failed));
278be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else if (mState == STATE_CANCELLED) {
279be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setAutoCancel(false);
28070fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen            notBuilder.setSmallIcon(mIncoming ? android.R.drawable.stat_sys_download_done :
28170fed93e7a684818495c6e27ab43fc05f7342926Martijn Coenen                    android.R.drawable.stat_sys_upload_done);
282be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setTicker(mContext.getString(R.string.beam_canceled));
283be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            notBuilder.setContentTitle(mContext.getString(R.string.beam_canceled));
284be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else {
285be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return;
286be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
287be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
288be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mNotificationManager.notify(null, mTransferId, notBuilder.build());
289be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
290be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
291be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    void updateStateAndNotification(int newState) {
292be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        this.mState = newState;
293be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        this.mLastUpdate = SystemClock.elapsedRealtime();
294be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
295f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen        mHandler.removeMessages(MSG_TRANSFER_TIMEOUT);
296f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen        if (isRunning()) {
297f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen            // Update timeout timer if we're still running
298be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            mHandler.sendEmptyMessageDelayed(MSG_TRANSFER_TIMEOUT, ALIVE_CHECK_MS);
299be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
300be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
301be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        updateNotification();
302be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
303be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if ((mState == STATE_SUCCESS || mState == STATE_FAILED || mState == STATE_CANCELLED)
304be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                && !mCalledBack) {
305be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            mCalledBack = true;
306be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            // Notify that we're done with this transfer
307be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            mCallback.onTransferComplete(this, mState == STATE_SUCCESS);
308be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
309be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
310be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
311be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    void processFiles() {
312be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // Check the amount of files we received in this transfer;
313be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // If more than one, create a separate directory for it.
314be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String extRoot = Environment.getExternalStorageDirectory().getPath();
315be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        File beamPath = new File(extRoot + "/" + BEAM_DIR);
316be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
317be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (!checkMediaStorage(beamPath) || mBtUris.size() == 0) {
318be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            Log.e(TAG, "Media storage not valid or no uris received.");
319be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            updateStateAndNotification(STATE_FAILED);
320be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return;
321be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
322be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
323be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mBtUris.size() > 1) {
324be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            beamPath = generateMultiplePath(extRoot + "/" + BEAM_DIR + "/");
325be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (!beamPath.isDirectory() && !beamPath.mkdir()) {
326be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                Log.e(TAG, "Failed to create multiple path " + beamPath.toString());
327be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                updateStateAndNotification(STATE_FAILED);
328be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                return;
329be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            }
330be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
331be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
332be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        for (int i = 0; i < mBtUris.size(); i++) {
333be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            Uri uri = mBtUris.get(i);
334be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            String mimeType = mBtMimeTypes.get(i);
335be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
336be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            File srcFile = new File(uri.getPath());
337be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
338be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            File dstFile = generateUniqueDestination(beamPath.getAbsolutePath(),
339be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                    uri.getLastPathSegment());
340be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (!srcFile.renameTo(dstFile)) {
341be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                if (DBG) Log.d(TAG, "Failed to rename from " + srcFile + " to " + dstFile);
342be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                srcFile.delete();
343be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                return;
344be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            } else {
345be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mPaths.add(dstFile.getAbsolutePath());
346be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mMimeTypes.put(dstFile.getAbsolutePath(), mimeType);
347be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                if (DBG) Log.d(TAG, "Did successful rename from " + srcFile + " to " + dstFile);
348be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            }
349be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
350be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
351be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // We can either add files to the media provider, or provide an ACTION_VIEW
352be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // intent to the file directly. We base this decision on the mime type
353be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // of the first file; if it's media the platform can deal with,
354be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // use the media provider, if it's something else, just launch an ACTION_VIEW
355be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // on the file.
356be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String mimeType = mMimeTypes.get(mPaths.get(0));
357be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mimeType.startsWith("image/") || mimeType.startsWith("video/") ||
358be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                mimeType.startsWith("audio/")) {
359be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            String[] arrayPaths = new String[mPaths.size()];
360be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            MediaScannerConnection.scanFile(mContext, mPaths.toArray(arrayPaths), null, this);
361be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            updateStateAndNotification(STATE_W4_MEDIA_SCANNER);
362be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else {
363be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            // We're done.
364be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            updateStateAndNotification(STATE_SUCCESS);
365be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
366be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
367be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
368be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
369be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public int getTransferId() {
370be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        return mTransferId;
371be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
372be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
373be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public boolean handleMessage(Message msg) {
374be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (msg.what == MSG_NEXT_TRANSFER_TIMER) {
375be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            // We didn't receive a new transfer in time, finalize this one
376be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (mIncoming) {
377be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                processFiles();
378be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            } else {
379d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                updateStateAndNotification(mSuccessCount > 0 ? STATE_SUCCESS : STATE_FAILED);
380be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            }
381be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return true;
382be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else if (msg.what == MSG_TRANSFER_TIMEOUT) {
383f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen            // No update on this transfer for a while, fail it.
384f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen            if (DBG) Log.d(TAG, "Transfer timed out for id: " + Integer.toString(mTransferId));
385f5a9550725ea1882b9e03d2e5f92c995d09cd84bMartijn Coenen            updateStateAndNotification(STATE_FAILED);
386be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
387be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        return false;
388be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
389be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
390be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    public synchronized void onScanCompleted(String path, Uri uri) {
391be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (DBG) Log.d(TAG, "Scan completed, path " + path + " uri " + uri);
392be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (uri != null) {
393be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            mMediaUris.put(path, uri);
394be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
395be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        mUrisScanned++;
396be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mUrisScanned == mPaths.size()) {
397be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            // We're done
398be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            updateStateAndNotification(STATE_SUCCESS);
399be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
400be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
401be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
402be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    boolean checkMediaStorage(File path) {
403be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
404be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            if (!path.isDirectory() && !path.mkdir()) {
405be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                Log.e(TAG, "Not dir or not mkdir " + path.getAbsolutePath());
406be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                return false;
407be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            }
408be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return true;
409be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else {
410be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            Log.e(TAG, "External storage not mounted, can't store file.");
411be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            return false;
412be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
413be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
414be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
415be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    Intent buildViewIntent() {
416be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (mPaths.size() == 0) return null;
417be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
418be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        Intent viewIntent = new Intent(Intent.ACTION_VIEW);
419be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
420be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String filePath = mPaths.get(0);
421be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        Uri mediaUri = mMediaUris.get(filePath);
422be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        Uri uri =  mediaUri != null ? mediaUri :
423be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            Uri.parse(ContentResolver.SCHEME_FILE + "://" + filePath);
424be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        viewIntent.setDataAndTypeAndNormalize(uri, mMimeTypes.get(filePath));
425be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        viewIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
426be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        return viewIntent;
427be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
428be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
429d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen    PendingIntent buildCancelIntent(boolean incoming) {
430be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        Intent intent = new Intent(HandoverService.ACTION_CANCEL_HANDOVER_TRANSFER);
431be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        intent.putExtra(HandoverService.EXTRA_SOURCE_ADDRESS, mRemoteDevice.getAddress());
432d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        intent.putExtra(HandoverService.EXTRA_INCOMING, incoming ? 1 : 0);
433d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen        PendingIntent pi = PendingIntent.getBroadcast(mContext, mTransferId, intent,
434d72546a022862a277e43499849e275e4e5ea209aMartijn Coenen                PendingIntent.FLAG_ONE_SHOT);
435be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
436be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        return pi;
437be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
438be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
439be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    File generateUniqueDestination(String path, String fileName) {
440be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        int dotIndex = fileName.lastIndexOf(".");
441be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String extension = null;
442be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String fileNameWithoutExtension = null;
443be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        if (dotIndex < 0) {
444be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            extension = "";
445be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            fileNameWithoutExtension = fileName;
446be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        } else {
447be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            extension = fileName.substring(dotIndex);
448be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            fileNameWithoutExtension = fileName.substring(0, dotIndex);
449be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
450be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        File dstFile = new File(path + File.separator + fileName);
451be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        int count = 0;
452be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        while (dstFile.exists()) {
453be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            dstFile = new File(path + File.separator + fileNameWithoutExtension + "-" +
454be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                    Integer.toString(count) + extension);
455be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            count++;
456be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
457be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        return dstFile;
458be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
459be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
460be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    File generateMultiplePath(String beamRoot) {
461be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        // Generate a unique directory with the date
462be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String format = "yyyy-MM-dd";
463116dfa0107cdc7ab098ed95828280542bf6b0a1eThe Android Open Source Project        SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.US);
464be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        String newPath = beamRoot + "beam-" + sdf.format(new Date());
465be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        File newFile = new File(newPath);
466be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        int count = 0;
467be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        while (newFile.exists()) {
468be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            newPath = beamRoot + "beam-" + sdf.format(new Date()) + "-" +
469be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project                    Integer.toString(count);
470be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            newFile = new File(newPath);
471be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project            count++;
472be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        }
473be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project        return newFile;
474be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project    }
475be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project}
476be1939b4b6003ac7a65fcb95a3912f5e1ce8e75fThe Android Open Source Project
477