1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib.bluetooth; 18 19 import android.bluetooth.BluetoothClass; 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothUuid; 22 import android.os.ParcelUuid; 23 import android.util.Log; 24 25 import com.android.internal.util.ArrayUtils; 26 27 /** 28 * BluetoothDeviceFilter contains a static method that returns a 29 * Filter object that returns whether or not the BluetoothDevice 30 * passed to it matches the specified filter type constant from 31 * {@link android.bluetooth.BluetoothDevicePicker}. 32 */ 33 public final class BluetoothDeviceFilter { 34 private static final String TAG = "BluetoothDeviceFilter"; 35 36 /** The filter interface to external classes. */ 37 public interface Filter { matches(BluetoothDevice device)38 boolean matches(BluetoothDevice device); 39 } 40 41 /** All filter singleton (referenced directly). */ 42 public static final Filter ALL_FILTER = new AllFilter(); 43 44 /** Bonded devices only filter (referenced directly). */ 45 public static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter(); 46 47 /** Unbonded devices only filter (referenced directly). */ 48 public static final Filter UNBONDED_DEVICE_FILTER = new UnbondedDeviceFilter(); 49 50 /** Table of singleton filter objects. */ 51 private static final Filter[] FILTERS = { 52 ALL_FILTER, // FILTER_TYPE_ALL 53 new AudioFilter(), // FILTER_TYPE_AUDIO 54 new TransferFilter(), // FILTER_TYPE_TRANSFER 55 new PanuFilter(), // FILTER_TYPE_PANU 56 new NapFilter() // FILTER_TYPE_NAP 57 }; 58 59 /** Private constructor. */ BluetoothDeviceFilter()60 private BluetoothDeviceFilter() { 61 } 62 63 /** 64 * Returns the singleton {@link Filter} object for the specified type, 65 * or {@link #ALL_FILTER} if the type value is out of range. 66 * 67 * @param filterType a constant from BluetoothDevicePicker 68 * @return a singleton object implementing the {@link Filter} interface. 69 */ getFilter(int filterType)70 public static Filter getFilter(int filterType) { 71 if (filterType >= 0 && filterType < FILTERS.length) { 72 return FILTERS[filterType]; 73 } else { 74 Log.w(TAG, "Invalid filter type " + filterType + " for device picker"); 75 return ALL_FILTER; 76 } 77 } 78 79 /** Filter that matches all devices. */ 80 private static final class AllFilter implements Filter { matches(BluetoothDevice device)81 public boolean matches(BluetoothDevice device) { 82 return true; 83 } 84 } 85 86 /** Filter that matches only bonded devices. */ 87 private static final class BondedDeviceFilter implements Filter { matches(BluetoothDevice device)88 public boolean matches(BluetoothDevice device) { 89 return device.getBondState() == BluetoothDevice.BOND_BONDED; 90 } 91 } 92 93 /** Filter that matches only unbonded devices. */ 94 private static final class UnbondedDeviceFilter implements Filter { matches(BluetoothDevice device)95 public boolean matches(BluetoothDevice device) { 96 return device.getBondState() != BluetoothDevice.BOND_BONDED; 97 } 98 } 99 100 /** Parent class of filters based on UUID and/or Bluetooth class. */ 101 private abstract static class ClassUuidFilter implements Filter { matches(ParcelUuid[] uuids, BluetoothClass btClass)102 abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass); 103 matches(BluetoothDevice device)104 public boolean matches(BluetoothDevice device) { 105 return matches(device.getUuids(), device.getBluetoothClass()); 106 } 107 } 108 109 /** Filter that matches devices that support AUDIO profiles. */ 110 private static final class AudioFilter extends ClassUuidFilter { 111 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)112 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 113 if (uuids != null) { 114 if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) { 115 return true; 116 } 117 if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) { 118 return true; 119 } 120 } else if (btClass != null) { 121 if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) || 122 btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) { 123 return true; 124 } 125 } 126 return false; 127 } 128 } 129 130 /** Filter that matches devices that support Object Transfer. */ 131 private static final class TransferFilter extends ClassUuidFilter { 132 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)133 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 134 if (uuids != null) { 135 if (ArrayUtils.contains(uuids, BluetoothUuid.OBEX_OBJECT_PUSH)) { 136 return true; 137 } 138 } 139 return btClass != null 140 && btClass.doesClassMatch(BluetoothClass.PROFILE_OPP); 141 } 142 } 143 144 /** Filter that matches devices that support PAN User (PANU) profile. */ 145 private static final class PanuFilter extends ClassUuidFilter { 146 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)147 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 148 if (uuids != null) { 149 if (ArrayUtils.contains(uuids, BluetoothUuid.PANU)) { 150 return true; 151 } 152 } 153 return btClass != null 154 && btClass.doesClassMatch(BluetoothClass.PROFILE_PANU); 155 } 156 } 157 158 /** Filter that matches devices that support NAP profile. */ 159 private static final class NapFilter extends ClassUuidFilter { 160 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)161 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 162 if (uuids != null) { 163 if (ArrayUtils.contains(uuids, BluetoothUuid.NAP)) { 164 return true; 165 } 166 } 167 return btClass != null 168 && btClass.doesClassMatch(BluetoothClass.PROFILE_NAP); 169 } 170 } 171 } 172