1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.settings.bluetooth;
18
19import android.bluetooth.BluetoothAdapter;
20import android.bluetooth.BluetoothDevice;
21import android.content.Context;
22import android.util.Log;
23
24import java.util.ArrayList;
25import java.util.Collection;
26import java.util.List;
27
28/**
29 * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
30 */
31final class CachedBluetoothDeviceManager {
32    private static final String TAG = "CachedBluetoothDeviceManager";
33    private static final boolean DEBUG = Utils.D;
34
35    private Context mContext;
36    private final List<CachedBluetoothDevice> mCachedDevices =
37            new ArrayList<CachedBluetoothDevice>();
38
39    CachedBluetoothDeviceManager(Context context) {
40        mContext = context;
41    }
42
43    public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
44        return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
45    }
46
47    public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
48        cachedDevice.setVisible(false);
49        return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
50    }
51
52    public void onDeviceNameUpdated(BluetoothDevice device) {
53        CachedBluetoothDevice cachedDevice = findDevice(device);
54        if (cachedDevice != null) {
55            cachedDevice.refreshName();
56        }
57    }
58
59    /**
60     * Search for existing {@link CachedBluetoothDevice} or return null
61     * if this device isn't in the cache. Use {@link #addDevice}
62     * to create and return a new {@link CachedBluetoothDevice} for
63     * a newly discovered {@link BluetoothDevice}.
64     *
65     * @param device the address of the Bluetooth device
66     * @return the cached device object for this device, or null if it has
67     *   not been previously seen
68     */
69    CachedBluetoothDevice findDevice(BluetoothDevice device) {
70        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
71            if (cachedDevice.getDevice().equals(device)) {
72                return cachedDevice;
73            }
74        }
75        return null;
76    }
77
78    /**
79     * Create and return a new {@link CachedBluetoothDevice}. This assumes
80     * that {@link #findDevice} has already been called and returned null.
81     * @param device the address of the new Bluetooth device
82     * @return the newly created CachedBluetoothDevice object
83     */
84    CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter,
85            LocalBluetoothProfileManager profileManager,
86            BluetoothDevice device) {
87        CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter,
88            profileManager, device);
89        mCachedDevices.add(newDevice);
90        return newDevice;
91    }
92
93    /**
94     * Attempts to get the name of a remote device, otherwise returns the address.
95     *
96     * @param device The remote device.
97     * @return The name, or if unavailable, the address.
98     */
99    public String getName(BluetoothDevice device) {
100        CachedBluetoothDevice cachedDevice = findDevice(device);
101        if (cachedDevice != null) {
102            return cachedDevice.getName();
103        }
104
105        String name = device.getAliasName();
106        if (name != null) {
107            return name;
108        }
109
110        return device.getAddress();
111    }
112
113    public synchronized void onScanningStateChanged(boolean started) {
114        if (!started) return;
115
116        // If starting a new scan, clear old visibility
117        // Iterate in reverse order since devices may be removed.
118        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
119            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
120            cachedDevice.setVisible(false);
121        }
122    }
123
124    public synchronized void onBtClassChanged(BluetoothDevice device) {
125        CachedBluetoothDevice cachedDevice = findDevice(device);
126        if (cachedDevice != null) {
127            cachedDevice.refreshBtClass();
128        }
129    }
130
131    public synchronized void onUuidChanged(BluetoothDevice device) {
132        CachedBluetoothDevice cachedDevice = findDevice(device);
133        if (cachedDevice != null) {
134            cachedDevice.onUuidChanged();
135        }
136    }
137
138    public synchronized void onBluetoothStateChanged(int bluetoothState) {
139        // When Bluetooth is turning off, we need to clear the non-bonded devices
140        // Otherwise, they end up showing up on the next BT enable
141        if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
142            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
143                CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
144                if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
145                   cachedDevice.setVisible(false);
146                   mCachedDevices.remove(i);
147                } else {
148                    // For bonded devices, we need to clear the connection status so that
149                    // when BT is enabled next time, device connection status shall be retrieved
150                    // by making a binder call.
151                    cachedDevice.clearProfileConnectionState();
152                }
153            }
154        }
155    }
156    private void log(String msg) {
157        if (DEBUG) {
158            Log.d(TAG, msg);
159        }
160    }
161}
162