109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/*
209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Copyright (c) 2008-2009, Motorola, Inc.
309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * All rights reserved.
509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * Redistribution and use in source and binary forms, with or without
709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * modification, are permitted provided that the following conditions are met:
809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Redistributions of source code must retain the above copyright notice,
1009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * this list of conditions and the following disclaimer.
1109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
1209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Redistributions in binary form must reproduce the above copyright notice,
1309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * this list of conditions and the following disclaimer in the documentation
1409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * and/or other materials provided with the distribution.
1509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
1609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * - Neither the name of the Motorola, Inc. nor the names of its contributors
1709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * may be used to endorse or promote products derived from this software
1809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * without specific prior written permission.
1909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly *
2009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * POSSIBILITY OF SUCH DAMAGE.
3109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */
3209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellypackage com.android.bluetooth.opp;
3409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
356769b59d715ea98bd72eafcfea9acd2714a887daTao Liejunimport com.android.bluetooth.R;
366769b59d715ea98bd72eafcfea9acd2714a887daTao Liejun
3709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Context;
3809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.app.Notification;
3909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.app.NotificationManager;
4009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.app.PendingIntent;
4109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.content.Intent;
4209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.database.Cursor;
4309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.net.Uri;
4409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport android.util.Log;
45eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Taoimport android.os.Handler;
46eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Taoimport android.os.Message;
471ac5507790a87810061a19dadec36eb328a222eaTao Liejunimport android.os.Process;
4809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyimport java.util.HashMap;
4909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
5009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly/**
5109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * This class handles the updating of the Notification Manager for the cases
5209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * where there is an ongoing transfer, incoming transfer need confirm and
5309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly * complete (successful or failed) transfer.
5409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly */
5509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pellyclass BluetoothOppNotification {
5609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private static final String TAG = "BluetoothOppNotification";
57ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly    private static final boolean V = Constants.VERBOSE;
5809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
5909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    static final String status = "(" + BluetoothShare.STATUS + " == '192'" + ")";
6009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
6109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    static final String visible = "(" + BluetoothShare.VISIBILITY + " IS NULL OR "
6209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            + BluetoothShare.VISIBILITY + " == '" + BluetoothShare.VISIBILITY_VISIBLE + "'" + ")";
6309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
6409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    static final String confirm = "(" + BluetoothShare.USER_CONFIRMATION + " == '"
6509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            + BluetoothShare.USER_CONFIRMATION_CONFIRMED + "' OR "
6609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            + BluetoothShare.USER_CONFIRMATION + " == '"
678099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            + BluetoothShare.USER_CONFIRMATION_AUTO_CONFIRMED  + "' OR "
688099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            + BluetoothShare.USER_CONFIRMATION + " == '"
698099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            + BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED + "'" + ")";
708099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen
718099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen    static final String not_through_handover = "(" + BluetoothShare.USER_CONFIRMATION + " != '"
728099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            + BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED + "'" + ")";
7309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
7409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    static final String WHERE_RUNNING = status + " AND " + visible + " AND " + confirm;
7509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
768099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen    static final String WHERE_COMPLETED = BluetoothShare.STATUS + " >= '200' AND " + visible +
778099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            " AND " + not_through_handover; // Don't show handover-initiated transfers
7809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
795cc617943765df27844e459362c4bc1821305216Lixin Yue    private static final String WHERE_COMPLETED_OUTBOUND = WHERE_COMPLETED + " AND " + "("
805cc617943765df27844e459362c4bc1821305216Lixin Yue            + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_OUTBOUND + ")";
815cc617943765df27844e459362c4bc1821305216Lixin Yue
825cc617943765df27844e459362c4bc1821305216Lixin Yue    private static final String WHERE_COMPLETED_INBOUND = WHERE_COMPLETED + " AND " + "("
835cc617943765df27844e459362c4bc1821305216Lixin Yue            + BluetoothShare.DIRECTION + " == " + BluetoothShare.DIRECTION_INBOUND + ")";
845cc617943765df27844e459362c4bc1821305216Lixin Yue
8509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    static final String WHERE_CONFIRM_PENDING = BluetoothShare.USER_CONFIRMATION + " == '"
8609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            + BluetoothShare.USER_CONFIRMATION_PENDING + "'" + " AND " + visible;
8709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
881ac5507790a87810061a19dadec36eb328a222eaTao Liejun    public NotificationManager mNotificationMgr;
891ac5507790a87810061a19dadec36eb328a222eaTao Liejun
901ac5507790a87810061a19dadec36eb328a222eaTao Liejun    private Context mContext;
911ac5507790a87810061a19dadec36eb328a222eaTao Liejun
921ac5507790a87810061a19dadec36eb328a222eaTao Liejun    private HashMap<String, NotificationItem> mNotifications;
931ac5507790a87810061a19dadec36eb328a222eaTao Liejun
941ac5507790a87810061a19dadec36eb328a222eaTao Liejun    private NotificationUpdateThread mUpdateNotificationThread;
951ac5507790a87810061a19dadec36eb328a222eaTao Liejun
96eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    private int mPendingUpdate = 0;
971ac5507790a87810061a19dadec36eb328a222eaTao Liejun
985cc617943765df27844e459362c4bc1821305216Lixin Yue    private static final int NOTIFICATION_ID_OUTBOUND = -1000005;
995cc617943765df27844e459362c4bc1821305216Lixin Yue
1005cc617943765df27844e459362c4bc1821305216Lixin Yue    private static final int NOTIFICATION_ID_INBOUND = -1000006;
1015cc617943765df27844e459362c4bc1821305216Lixin Yue
1025cc617943765df27844e459362c4bc1821305216Lixin Yue    private boolean mUpdateCompleteNotification = true;
1035cc617943765df27844e459362c4bc1821305216Lixin Yue
1045cc617943765df27844e459362c4bc1821305216Lixin Yue    private int mActiveNotificationId = 0;
1055cc617943765df27844e459362c4bc1821305216Lixin Yue
10609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
10709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * This inner class is used to describe some properties for one transfer.
10809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
10909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    static class NotificationItem {
11009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int id; // This first field _id in db;
11109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int direction; // to indicate sending or receiving
11309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int totalCurrent = 0; // current transfer bytes
11509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
11609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        int totalTotal = 0; // total bytes for current transfer
11709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
1185cb59523d7d7e25c58bd99c100c50e49c78481ceMatthew Xie        long timeStamp = 0; // Database time stamp. Used for sorting ongoing transfers.
11974e5eba4a45ecca87eec3ac1762ca527cc614d78erik.ljungberg
12009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        String description; // the text above progress bar
1218099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen
1228099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen        boolean handoverInitiated = false; // transfer initiated by connection handover (eg NFC)
1237a4cc5c2f6ec06e8dc6f930680ce9aceff6df359Martijn Coenen
1247a4cc5c2f6ec06e8dc6f930680ce9aceff6df359Martijn Coenen        String destination; // destination associated with this transfer
12509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
12609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
12709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
12809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Constructor
129239bc526513429995c61c4148c105725c395b1a9Jackson Fan     *
130239bc526513429995c61c4148c105725c395b1a9Jackson Fan     * @param ctx The context to use to obtain access to the Notification
131239bc526513429995c61c4148c105725c395b1a9Jackson Fan     *            Service
13209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
13309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    BluetoothOppNotification(Context ctx) {
13409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mContext = ctx;
13509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mNotificationMgr = (NotificationManager)mContext
13609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                .getSystemService(Context.NOTIFICATION_SERVICE);
13709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mNotifications = new HashMap<String, NotificationItem>();
13809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
13909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
14009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    /**
14109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     * Update the notification ui.
14209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly     */
14309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    public void updateNotification() {
144c6f1bacf1d4c39d7efd5dc98004d936c18ed51f1Lixin Yue        synchronized (BluetoothOppNotification.this) {
145eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            mPendingUpdate++;
146eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            if (mPendingUpdate > 1) {
147eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                if (V) Log.v(TAG, "update too frequent, put in queue");
148eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                return;
149eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            }
150eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            if (!mHandler.hasMessages(NOTIFY)) {
151eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                if (V) Log.v(TAG, "send message");
152eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                mHandler.sendMessage(mHandler.obtainMessage(NOTIFY));
1531ac5507790a87810061a19dadec36eb328a222eaTao Liejun            }
1541ac5507790a87810061a19dadec36eb328a222eaTao Liejun        }
1551ac5507790a87810061a19dadec36eb328a222eaTao Liejun    }
1561ac5507790a87810061a19dadec36eb328a222eaTao Liejun
157eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    private static final int NOTIFY = 0;
158eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    // Use 1 second timer to limit notification frequency.
159eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    // 1. On the first notification, create the update thread.
160eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    //    Buffer other updates.
161eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    // 2. Update thread will clear mPendingUpdate.
162eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    // 3. Handler sends a delayed message to self
163eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    // 4. Handler checks if there are any more updates after 1 second.
164eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    // 5. If there is an update, update it else stop.
165eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    private Handler mHandler = new Handler() {
166eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao        public void handleMessage(Message msg) {
167eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            switch (msg.what) {
168eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                case NOTIFY:
169eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                    synchronized (BluetoothOppNotification.this) {
170eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                        if (mPendingUpdate > 0 && mUpdateNotificationThread == null) {
171eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            if (V) Log.v(TAG, "new notify threadi!");
172eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            mUpdateNotificationThread = new NotificationUpdateThread();
173eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            mUpdateNotificationThread.start();
174eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            if (V) Log.v(TAG, "send delay message");
175eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            mHandler.sendMessageDelayed(mHandler.obtainMessage(NOTIFY), 1000);
176eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                        } else if (mPendingUpdate > 0) {
177eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            if (V) Log.v(TAG, "previous thread is not finished yet");
178eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            mHandler.sendMessageDelayed(mHandler.obtainMessage(NOTIFY), 1000);
179eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                        }
180eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                        break;
181eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                    }
182eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao              }
183eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao         }
184eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao    };
185eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao
1861ac5507790a87810061a19dadec36eb328a222eaTao Liejun    private class NotificationUpdateThread extends Thread {
1871ac5507790a87810061a19dadec36eb328a222eaTao Liejun
1881ac5507790a87810061a19dadec36eb328a222eaTao Liejun        public NotificationUpdateThread() {
1891ac5507790a87810061a19dadec36eb328a222eaTao Liejun            super("Notification Update Thread");
1901ac5507790a87810061a19dadec36eb328a222eaTao Liejun        }
1911ac5507790a87810061a19dadec36eb328a222eaTao Liejun
1921ac5507790a87810061a19dadec36eb328a222eaTao Liejun        @Override
1931ac5507790a87810061a19dadec36eb328a222eaTao Liejun        public void run() {
1941ac5507790a87810061a19dadec36eb328a222eaTao Liejun            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
195eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            synchronized (BluetoothOppNotification.this) {
196eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                if (mUpdateNotificationThread != this) {
197eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                    throw new IllegalStateException(
198eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                            "multiple UpdateThreads in BluetoothOppNotification");
1991ac5507790a87810061a19dadec36eb328a222eaTao Liejun                }
200eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                mPendingUpdate = 0;
201eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            }
202eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            updateActiveNotification();
203eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            updateCompletedNotification();
204eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            updateIncomingFileConfirmNotification();
205eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao            synchronized (BluetoothOppNotification.this) {
206eb77c4b1d9aa71d7dd8dd934e9d1971583f9c0e2Liejun Tao                mUpdateNotificationThread = null;
2071ac5507790a87810061a19dadec36eb328a222eaTao Liejun            }
2081ac5507790a87810061a19dadec36eb328a222eaTao Liejun        }
20909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
21009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
21109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void updateActiveNotification() {
21209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        // Active transfers
21309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
21409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                WHERE_RUNNING, null, BluetoothShare._ID);
21509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (cursor == null) {
21609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return;
21709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
21809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
2195cc617943765df27844e459362c4bc1821305216Lixin Yue        // If there is active transfers, then no need to update completed transfer
2205cc617943765df27844e459362c4bc1821305216Lixin Yue        // notifications
2215cc617943765df27844e459362c4bc1821305216Lixin Yue        if (cursor.getCount() > 0) {
2225cc617943765df27844e459362c4bc1821305216Lixin Yue            mUpdateCompleteNotification = false;
2235cc617943765df27844e459362c4bc1821305216Lixin Yue        } else {
2245cc617943765df27844e459362c4bc1821305216Lixin Yue            mUpdateCompleteNotification = true;
2255cc617943765df27844e459362c4bc1821305216Lixin Yue        }
2265cc617943765df27844e459362c4bc1821305216Lixin Yue        if (V) Log.v(TAG, "mUpdateCompleteNotification = " + mUpdateCompleteNotification);
2275cc617943765df27844e459362c4bc1821305216Lixin Yue
22809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        // Collate the notifications
2295cc617943765df27844e459362c4bc1821305216Lixin Yue        final int timestampIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP);
2305cc617943765df27844e459362c4bc1821305216Lixin Yue        final int directionIndex = cursor.getColumnIndexOrThrow(BluetoothShare.DIRECTION);
2315cc617943765df27844e459362c4bc1821305216Lixin Yue        final int idIndex = cursor.getColumnIndexOrThrow(BluetoothShare._ID);
2325cc617943765df27844e459362c4bc1821305216Lixin Yue        final int totalBytesIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TOTAL_BYTES);
2335cc617943765df27844e459362c4bc1821305216Lixin Yue        final int currentBytesIndex = cursor.getColumnIndexOrThrow(BluetoothShare.CURRENT_BYTES);
2345cc617943765df27844e459362c4bc1821305216Lixin Yue        final int dataIndex = cursor.getColumnIndexOrThrow(BluetoothShare._DATA);
2355cc617943765df27844e459362c4bc1821305216Lixin Yue        final int filenameHintIndex = cursor.getColumnIndexOrThrow(BluetoothShare.FILENAME_HINT);
2368099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen        final int confirmIndex = cursor.getColumnIndexOrThrow(BluetoothShare.USER_CONFIRMATION);
2377a4cc5c2f6ec06e8dc6f930680ce9aceff6df359Martijn Coenen        final int destinationIndex = cursor.getColumnIndexOrThrow(BluetoothShare.DESTINATION);
2385cc617943765df27844e459362c4bc1821305216Lixin Yue
23909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        mNotifications.clear();
24009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
2415cb59523d7d7e25c58bd99c100c50e49c78481ceMatthew Xie            long timeStamp = cursor.getLong(timestampIndex);
2425cc617943765df27844e459362c4bc1821305216Lixin Yue            int dir = cursor.getInt(directionIndex);
2435cc617943765df27844e459362c4bc1821305216Lixin Yue            int id = cursor.getInt(idIndex);
2445cc617943765df27844e459362c4bc1821305216Lixin Yue            int total = cursor.getInt(totalBytesIndex);
2455cc617943765df27844e459362c4bc1821305216Lixin Yue            int current = cursor.getInt(currentBytesIndex);
2468099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            int confirmation = cursor.getInt(confirmIndex);
24709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
2487a4cc5c2f6ec06e8dc6f930680ce9aceff6df359Martijn Coenen            String destination = cursor.getString(destinationIndex);
2495cc617943765df27844e459362c4bc1821305216Lixin Yue            String fileName = cursor.getString(dataIndex);
25009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (fileName == null) {
2515cc617943765df27844e459362c4bc1821305216Lixin Yue                fileName = cursor.getString(filenameHintIndex);
25209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
25309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (fileName == null) {
25409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                fileName = mContext.getString(R.string.unknown_file);
25509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
25609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            String batchID = Long.toString(timeStamp);
25809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
25909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            // sending objects in one batch has same timeStamp
26009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (mNotifications.containsKey(batchID)) {
26109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                // NOTE: currently no such case
26209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                // Batch sending case
26309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
26409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                NotificationItem item = new NotificationItem();
26574e5eba4a45ecca87eec3ac1762ca527cc614d78erik.ljungberg                item.timeStamp = timeStamp;
26609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                item.id = id;
26709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                item.direction = dir;
26809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) {
269239bc526513429995c61c4148c105725c395b1a9Jackson Fan                    item.description = mContext.getString(R.string.notification_sending, fileName);
27009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) {
271239bc526513429995c61c4148c105725c395b1a9Jackson Fan                    item.description = mContext
272239bc526513429995c61c4148c105725c395b1a9Jackson Fan                            .getString(R.string.notification_receiving, fileName);
27309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                } else {
274ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                    if (V) Log.v(TAG, "mDirection ERROR!");
27509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                }
27609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                item.totalCurrent = current;
27709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                item.totalTotal = total;
2788099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                item.handoverInitiated =
2798099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                        confirmation == BluetoothShare.USER_CONFIRMATION_HANDOVER_CONFIRMED;
2807a4cc5c2f6ec06e8dc6f930680ce9aceff6df359Martijn Coenen                item.destination = destination;
28109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                mNotifications.put(batchID, item);
28209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
283ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (V) Log.v(TAG, "ID=" + item.id + "; batchID=" + batchID + "; totoalCurrent"
28409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                            + item.totalCurrent + "; totalTotal=" + item.totalTotal);
28509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
28609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
28709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        cursor.close();
28809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
28909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        // Add the notifications
29009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        for (NotificationItem item : mNotifications.values()) {
2918099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            if (item.handoverInitiated) {
2928099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                float progress = 0;
2938099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                if (item.totalTotal == -1) {
2948099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                    progress = -1;
2958099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                } else {
2968099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                    progress = (float)item.totalCurrent / item.totalTotal;
2978099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                }
2988099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen
2998099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                // Let NFC service deal with notifications for this transfer
3008099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                Intent intent = new Intent(Constants.ACTION_BT_OPP_TRANSFER_PROGRESS);
3018099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                if (item.direction == BluetoothShare.DIRECTION_INBOUND) {
3028099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                    intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_DIRECTION,
3038099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                            Constants.DIRECTION_BLUETOOTH_INCOMING);
3048099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                } else {
3058099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                    intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_DIRECTION,
3068099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                            Constants.DIRECTION_BLUETOOTH_OUTGOING);
3078099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                }
3088099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_ID, item.id);
3098099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                intent.putExtra(Constants.EXTRA_BT_OPP_TRANSFER_PROGRESS, progress);
3107a4cc5c2f6ec06e8dc6f930680ce9aceff6df359Martijn Coenen                intent.putExtra(Constants.EXTRA_BT_OPP_ADDRESS, item.destination);
3118099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                mContext.sendBroadcast(intent, Constants.HANDOVER_STATUS_PERMISSION);
3128099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen                continue;
3138099f5e7bfa7227ba674b5f0076f331e737bafd7Martijn Coenen            }
31409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            // Build the notification object
315dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            // TODO: split description into two rows with filename in second row
316dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            Notification.Builder b = new Notification.Builder(mContext);
317dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            b.setContentTitle(item.description);
318dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            b.setContentInfo(
319dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby                    BluetoothOppUtility.formatProgressText(item.totalTotal, item.totalCurrent));
320dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            b.setProgress(item.totalTotal, item.totalCurrent, item.totalTotal == -1);
321dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            b.setWhen(item.timeStamp);
32209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (item.direction == BluetoothShare.DIRECTION_OUTBOUND) {
323dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby                b.setSmallIcon(android.R.drawable.stat_sys_upload);
32409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else if (item.direction == BluetoothShare.DIRECTION_INBOUND) {
325dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby                b.setSmallIcon(android.R.drawable.stat_sys_download);
32609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
327ce4d93666275df294cb073fe41de5b85932570a8Nick Pelly                if (V) Log.v(TAG, "mDirection ERROR!");
32809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
329dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            b.setOngoing(true);
33009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
33109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Intent intent = new Intent(Constants.ACTION_LIST);
33209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
33309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent.setData(Uri.parse(BluetoothShare.CONTENT_URI + "/" + item.id));
33409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
335dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            b.setContentIntent(PendingIntent.getBroadcast(mContext, 0, intent, 0));
336dec631a77ab9cc89c4d3867b80cfe300e7cf83e9Jake Hamby            mNotificationMgr.notify(item.id, b.getNotification());
3375cc617943765df27844e459362c4bc1821305216Lixin Yue
3385cc617943765df27844e459362c4bc1821305216Lixin Yue            mActiveNotificationId = item.id;
33909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
34009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
34109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
34209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void updateCompletedNotification() {
3435cc617943765df27844e459362c4bc1821305216Lixin Yue        String title;
3445cc617943765df27844e459362c4bc1821305216Lixin Yue        String caption;
3455cc617943765df27844e459362c4bc1821305216Lixin Yue        long timeStamp = 0;
3465cc617943765df27844e459362c4bc1821305216Lixin Yue        int outboundSuccNumber = 0;
3475cc617943765df27844e459362c4bc1821305216Lixin Yue        int outboundFailNumber = 0;
3485cc617943765df27844e459362c4bc1821305216Lixin Yue        int outboundNum;
3495cc617943765df27844e459362c4bc1821305216Lixin Yue        int inboundNum;
3505cc617943765df27844e459362c4bc1821305216Lixin Yue        int inboundSuccNumber = 0;
3515cc617943765df27844e459362c4bc1821305216Lixin Yue        int inboundFailNumber = 0;
3525cc617943765df27844e459362c4bc1821305216Lixin Yue        Intent intent;
3535cc617943765df27844e459362c4bc1821305216Lixin Yue
3545cc617943765df27844e459362c4bc1821305216Lixin Yue        // If there is active transfer, no need to update complete transfer
3555cc617943765df27844e459362c4bc1821305216Lixin Yue        // notification
3565cc617943765df27844e459362c4bc1821305216Lixin Yue        if (!mUpdateCompleteNotification) {
3575cc617943765df27844e459362c4bc1821305216Lixin Yue            if (V) Log.v(TAG, "No need to update complete notification");
3585cc617943765df27844e459362c4bc1821305216Lixin Yue            return;
3595cc617943765df27844e459362c4bc1821305216Lixin Yue        }
3605cc617943765df27844e459362c4bc1821305216Lixin Yue
3615cc617943765df27844e459362c4bc1821305216Lixin Yue        // After merge complete notifications to 2 notifications, there is no
3625cc617943765df27844e459362c4bc1821305216Lixin Yue        // chance to update the active notifications to complete notifications
3635cc617943765df27844e459362c4bc1821305216Lixin Yue        // as before. So need cancel the active notification after the active
3645cc617943765df27844e459362c4bc1821305216Lixin Yue        // transfer becomes complete.
3655cc617943765df27844e459362c4bc1821305216Lixin Yue        if (mNotificationMgr != null && mActiveNotificationId != 0) {
3665cc617943765df27844e459362c4bc1821305216Lixin Yue            mNotificationMgr.cancel(mActiveNotificationId);
3675cc617943765df27844e459362c4bc1821305216Lixin Yue            if (V) Log.v(TAG, "ongoing transfer notification was removed");
3685cc617943765df27844e459362c4bc1821305216Lixin Yue        }
3695cc617943765df27844e459362c4bc1821305216Lixin Yue
3705cc617943765df27844e459362c4bc1821305216Lixin Yue        // Creating outbound notification
37109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
3725cc617943765df27844e459362c4bc1821305216Lixin Yue                WHERE_COMPLETED_OUTBOUND, null, BluetoothShare.TIMESTAMP + " DESC");
37309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (cursor == null) {
37409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return;
37509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
37609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3775cc617943765df27844e459362c4bc1821305216Lixin Yue        final int timestampIndex = cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP);
3785cc617943765df27844e459362c4bc1821305216Lixin Yue        final int statusIndex = cursor.getColumnIndexOrThrow(BluetoothShare.STATUS);
37909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3805cc617943765df27844e459362c4bc1821305216Lixin Yue        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
3815cc617943765df27844e459362c4bc1821305216Lixin Yue            if (cursor.isFirst()) {
3825cc617943765df27844e459362c4bc1821305216Lixin Yue                // Display the time for the latest transfer
3835cc617943765df27844e459362c4bc1821305216Lixin Yue                timeStamp = cursor.getLong(timestampIndex);
38409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
3855cc617943765df27844e459362c4bc1821305216Lixin Yue            int status = cursor.getInt(statusIndex);
38609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
38709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            if (BluetoothShare.isStatusError(status)) {
3885cc617943765df27844e459362c4bc1821305216Lixin Yue                outboundFailNumber++;
38909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            } else {
3905cc617943765df27844e459362c4bc1821305216Lixin Yue                outboundSuccNumber++;
39109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            }
3925cc617943765df27844e459362c4bc1821305216Lixin Yue        }
3935cc617943765df27844e459362c4bc1821305216Lixin Yue        if (V) Log.v(TAG, "outbound: succ-" + outboundSuccNumber + "  fail-" + outboundFailNumber);
3945cc617943765df27844e459362c4bc1821305216Lixin Yue        cursor.close();
39509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
3965cc617943765df27844e459362c4bc1821305216Lixin Yue        outboundNum = outboundSuccNumber + outboundFailNumber;
3975cc617943765df27844e459362c4bc1821305216Lixin Yue        // create the outbound notification
398509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue        if (outboundNum > 0) {
399de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            Notification outNoti = new Notification();
400de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            outNoti.icon = android.R.drawable.stat_sys_upload_done;
401509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue            title = mContext.getString(R.string.outbound_noti_title);
4025cc617943765df27844e459362c4bc1821305216Lixin Yue            caption = mContext.getString(R.string.noti_caption, outboundSuccNumber,
4035cc617943765df27844e459362c4bc1821305216Lixin Yue                    outboundFailNumber);
404509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue            intent = new Intent(Constants.ACTION_OPEN_OUTBOUND_TRANSFER);
405509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
406de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            outNoti.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(
4075cc617943765df27844e459362c4bc1821305216Lixin Yue                    mContext, 0, intent, 0));
408ec6f2d44491bf1e3ffa7c75875985f9c16cf721dLixin Yue            intent = new Intent(Constants.ACTION_COMPLETE_HIDE);
409ec6f2d44491bf1e3ffa7c75875985f9c16cf721dLixin Yue            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
410ec6f2d44491bf1e3ffa7c75875985f9c16cf721dLixin Yue            outNoti.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
411de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            outNoti.when = timeStamp;
412de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            mNotificationMgr.notify(NOTIFICATION_ID_OUTBOUND, outNoti);
4135cc617943765df27844e459362c4bc1821305216Lixin Yue        } else {
414de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            if (mNotificationMgr != null) {
4155cc617943765df27844e459362c4bc1821305216Lixin Yue                mNotificationMgr.cancel(NOTIFICATION_ID_OUTBOUND);
4165cc617943765df27844e459362c4bc1821305216Lixin Yue                if (V) Log.v(TAG, "outbound notification was removed.");
4175cc617943765df27844e459362c4bc1821305216Lixin Yue            }
4185cc617943765df27844e459362c4bc1821305216Lixin Yue        }
4195cc617943765df27844e459362c4bc1821305216Lixin Yue
4205cc617943765df27844e459362c4bc1821305216Lixin Yue        // Creating inbound notification
4215cc617943765df27844e459362c4bc1821305216Lixin Yue        cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
4225cc617943765df27844e459362c4bc1821305216Lixin Yue                WHERE_COMPLETED_INBOUND, null, BluetoothShare.TIMESTAMP + " DESC");
4235cc617943765df27844e459362c4bc1821305216Lixin Yue        if (cursor == null) {
4245cc617943765df27844e459362c4bc1821305216Lixin Yue            return;
4255cc617943765df27844e459362c4bc1821305216Lixin Yue        }
42609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
4275cc617943765df27844e459362c4bc1821305216Lixin Yue        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
4285cc617943765df27844e459362c4bc1821305216Lixin Yue            if (cursor.isFirst()) {
4295cc617943765df27844e459362c4bc1821305216Lixin Yue                // Display the time for the latest transfer
4305cc617943765df27844e459362c4bc1821305216Lixin Yue                timeStamp = cursor.getLong(timestampIndex);
4315cc617943765df27844e459362c4bc1821305216Lixin Yue            }
4325cc617943765df27844e459362c4bc1821305216Lixin Yue            int status = cursor.getInt(statusIndex);
4335cc617943765df27844e459362c4bc1821305216Lixin Yue
4345cc617943765df27844e459362c4bc1821305216Lixin Yue            if (BluetoothShare.isStatusError(status)) {
4355cc617943765df27844e459362c4bc1821305216Lixin Yue                inboundFailNumber++;
4365cc617943765df27844e459362c4bc1821305216Lixin Yue            } else {
4375cc617943765df27844e459362c4bc1821305216Lixin Yue                inboundSuccNumber++;
4385cc617943765df27844e459362c4bc1821305216Lixin Yue            }
43909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
4405cc617943765df27844e459362c4bc1821305216Lixin Yue        if (V) Log.v(TAG, "inbound: succ-" + inboundSuccNumber + "  fail-" + inboundFailNumber);
44109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        cursor.close();
4425cc617943765df27844e459362c4bc1821305216Lixin Yue
4435cc617943765df27844e459362c4bc1821305216Lixin Yue        inboundNum = inboundSuccNumber + inboundFailNumber;
4445cc617943765df27844e459362c4bc1821305216Lixin Yue        // create the inbound notification
445509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue        if (inboundNum > 0) {
446de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            Notification inNoti = new Notification();
447de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            inNoti.icon = android.R.drawable.stat_sys_download_done;
448509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue            title = mContext.getString(R.string.inbound_noti_title);
4495cc617943765df27844e459362c4bc1821305216Lixin Yue            caption = mContext.getString(R.string.noti_caption, inboundSuccNumber,
4505cc617943765df27844e459362c4bc1821305216Lixin Yue                    inboundFailNumber);
451509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue            intent = new Intent(Constants.ACTION_OPEN_INBOUND_TRANSFER);
452509a6cd43906cce5f9bc78a83bd2058a4e5249e7Lixin Yue            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
453de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            inNoti.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(
4545cc617943765df27844e459362c4bc1821305216Lixin Yue                    mContext, 0, intent, 0));
455ec6f2d44491bf1e3ffa7c75875985f9c16cf721dLixin Yue            intent = new Intent(Constants.ACTION_COMPLETE_HIDE);
456ec6f2d44491bf1e3ffa7c75875985f9c16cf721dLixin Yue            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
457ec6f2d44491bf1e3ffa7c75875985f9c16cf721dLixin Yue            inNoti.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
458de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            inNoti.when = timeStamp;
459de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            mNotificationMgr.notify(NOTIFICATION_ID_INBOUND, inNoti);
4605cc617943765df27844e459362c4bc1821305216Lixin Yue        } else {
461de773e60fed15a4ad13325089a5609c9bc6ede59Lixin Yue            if (mNotificationMgr != null) {
4625cc617943765df27844e459362c4bc1821305216Lixin Yue                mNotificationMgr.cancel(NOTIFICATION_ID_INBOUND);
4635cc617943765df27844e459362c4bc1821305216Lixin Yue                if (V) Log.v(TAG, "inbound notification was removed.");
4645cc617943765df27844e459362c4bc1821305216Lixin Yue            }
4655cc617943765df27844e459362c4bc1821305216Lixin Yue        }
46609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
46709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
46809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    private void updateIncomingFileConfirmNotification() {
46909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        Cursor cursor = mContext.getContentResolver().query(BluetoothShare.CONTENT_URI, null,
47009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                WHERE_CONFIRM_PENDING, null, BluetoothShare._ID);
47109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
47209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        if (cursor == null) {
47309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            return;
47409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
47509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
47609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
477b0b662a98d8b7c099ee706d0e08bd239adcdffc7Jaikumar Ganesh            CharSequence title =
478b0b662a98d8b7c099ee706d0e08bd239adcdffc7Jaikumar Ganesh                    mContext.getText(R.string.incoming_file_confirm_Notification_title);
479b0b662a98d8b7c099ee706d0e08bd239adcdffc7Jaikumar Ganesh            CharSequence caption = mContext
480b0b662a98d8b7c099ee706d0e08bd239adcdffc7Jaikumar Ganesh                    .getText(R.string.incoming_file_confirm_Notification_caption);
48109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            int id = cursor.getInt(cursor.getColumnIndexOrThrow(BluetoothShare._ID));
482dc3bacd6eb626a93f2c3c4c62b3ef6aa9e575d92Lixin Yue            long timeStamp = cursor.getLong(cursor.getColumnIndexOrThrow(BluetoothShare.TIMESTAMP));
48309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Uri contentUri = Uri.parse(BluetoothShare.CONTENT_URI + "/" + id);
48409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
48509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Notification n = new Notification();
486464d9d216ab1a6cf192e3e526596073c7e35e4a7L.X.YUE            n.icon = R.drawable.bt_incomming_file_notification;
48709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            n.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
488b0b662a98d8b7c099ee706d0e08bd239adcdffc7Jaikumar Ganesh            n.flags |= Notification.FLAG_ONGOING_EVENT;
48909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            n.defaults = Notification.DEFAULT_SOUND;
49009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            n.tickerText = title;
491b0b662a98d8b7c099ee706d0e08bd239adcdffc7Jaikumar Ganesh
49209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM);
49309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
49409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent.setData(contentUri);
4956ee2d0e0405a074cf827e0c0ac4bfbffd1850ceaLixin Yue
4966ee2d0e0405a074cf827e0c0ac4bfbffd1850ceaLixin Yue            n.when = timeStamp;
49709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0,
49809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly                    intent, 0));
49909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
50009e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent = new Intent(Constants.ACTION_HIDE);
50109e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
50209e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            intent.setData(contentUri);
50309e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
50409e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly
50509e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly            mNotificationMgr.notify(id, n);
50609e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        }
50709e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly        cursor.close();
50809e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly    }
50909e9cba205af60b3f42e7a4d891a7d1392e1f2a5Nick Pelly}
510