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.annotation.SuppressLint; 20 import android.bluetooth.BluetoothClass; 21 import android.bluetooth.BluetoothDevice; 22 import android.bluetooth.BluetoothUuid; 23 import android.os.ParcelUuid; 24 import android.util.Log; 25 26 import com.android.internal.util.ArrayUtils; 27 28 /** 29 * BluetoothDeviceFilter contains a static method that returns a 30 * Filter object that returns whether or not the BluetoothDevice 31 * passed to it matches the specified filter type constant from 32 * {@link android.bluetooth.BluetoothDevicePicker}. 33 */ 34 public final class BluetoothDeviceFilter { 35 private static final String TAG = "BluetoothDeviceFilter"; 36 37 /** The filter interface to external classes. */ 38 public interface Filter { matches(BluetoothDevice device)39 boolean matches(BluetoothDevice device); 40 } 41 42 /** All filter singleton (referenced directly). */ 43 public static final Filter ALL_FILTER = new AllFilter(); 44 45 /** Bonded devices only filter (referenced directly). */ 46 public static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter(); 47 48 /** Unbonded devices only filter (referenced directly). */ 49 public static final Filter UNBONDED_DEVICE_FILTER = new UnbondedDeviceFilter(); 50 51 /** Table of singleton filter objects. */ 52 private static final Filter[] FILTERS = { 53 ALL_FILTER, // FILTER_TYPE_ALL 54 new AudioFilter(), // FILTER_TYPE_AUDIO 55 new TransferFilter(), // FILTER_TYPE_TRANSFER 56 new PanuFilter(), // FILTER_TYPE_PANU 57 new NapFilter() // FILTER_TYPE_NAP 58 }; 59 60 /** Private constructor. */ BluetoothDeviceFilter()61 private BluetoothDeviceFilter() { 62 } 63 64 /** 65 * Returns the singleton {@link Filter} object for the specified type, 66 * or {@link #ALL_FILTER} if the type value is out of range. 67 * 68 * @param filterType a constant from BluetoothDevicePicker 69 * @return a singleton object implementing the {@link Filter} interface. 70 */ getFilter(int filterType)71 public static Filter getFilter(int filterType) { 72 if (filterType >= 0 && filterType < FILTERS.length) { 73 return FILTERS[filterType]; 74 } else { 75 Log.w(TAG, "Invalid filter type " + filterType + " for device picker"); 76 return ALL_FILTER; 77 } 78 } 79 80 /** Filter that matches all devices. */ 81 private static final class AllFilter implements Filter { matches(BluetoothDevice device)82 public boolean matches(BluetoothDevice device) { 83 return true; 84 } 85 } 86 87 /** Filter that matches only bonded devices. */ 88 private static final class BondedDeviceFilter implements Filter { matches(BluetoothDevice device)89 public boolean matches(BluetoothDevice device) { 90 return device.getBondState() == BluetoothDevice.BOND_BONDED; 91 } 92 } 93 94 /** Filter that matches only unbonded devices. */ 95 private static final class UnbondedDeviceFilter implements Filter { matches(BluetoothDevice device)96 public boolean matches(BluetoothDevice device) { 97 return device.getBondState() != BluetoothDevice.BOND_BONDED; 98 } 99 } 100 101 /** Parent class of filters based on UUID and/or Bluetooth class. */ 102 private abstract static class ClassUuidFilter implements Filter { matches(ParcelUuid[] uuids, BluetoothClass btClass)103 abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass); 104 matches(BluetoothDevice device)105 public boolean matches(BluetoothDevice device) { 106 return matches(device.getUuids(), device.getBluetoothClass()); 107 } 108 } 109 110 /** Filter that matches devices that support AUDIO profiles. */ 111 private static final class AudioFilter extends ClassUuidFilter { 112 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)113 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 114 if (uuids != null) { 115 if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) { 116 return true; 117 } 118 if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) { 119 return true; 120 } 121 } else if (btClass != null) { 122 if (doesClassMatch(btClass, BluetoothClass.PROFILE_A2DP) 123 || doesClassMatch(btClass, BluetoothClass.PROFILE_HEADSET)) { 124 return true; 125 } 126 } 127 return false; 128 } 129 } 130 131 /** Filter that matches devices that support Object Transfer. */ 132 private static final class TransferFilter extends ClassUuidFilter { 133 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)134 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 135 if (uuids != null) { 136 if (ArrayUtils.contains(uuids, BluetoothUuid.OBEX_OBJECT_PUSH)) { 137 return true; 138 } 139 } 140 return btClass != null 141 && doesClassMatch(btClass, BluetoothClass.PROFILE_OPP); 142 } 143 } 144 145 /** Filter that matches devices that support PAN User (PANU) profile. */ 146 private static final class PanuFilter extends ClassUuidFilter { 147 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)148 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 149 if (uuids != null) { 150 if (ArrayUtils.contains(uuids, BluetoothUuid.PANU)) { 151 return true; 152 } 153 } 154 return btClass != null 155 && doesClassMatch(btClass, BluetoothClass.PROFILE_PANU); 156 } 157 } 158 159 /** Filter that matches devices that support NAP profile. */ 160 private static final class NapFilter extends ClassUuidFilter { 161 @Override matches(ParcelUuid[] uuids, BluetoothClass btClass)162 boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) { 163 if (uuids != null) { 164 if (ArrayUtils.contains(uuids, BluetoothUuid.NAP)) { 165 return true; 166 } 167 } 168 return btClass != null 169 && doesClassMatch(btClass, BluetoothClass.PROFILE_NAP); 170 } 171 } 172 173 @SuppressLint("NewApi") // Hidden API made public doesClassMatch(BluetoothClass btClass, int classId)174 private static boolean doesClassMatch(BluetoothClass btClass, int classId) { 175 return btClass.doesClassMatch(classId); 176 } 177 } 178