1 /* 2 * Copyright (C) 2013 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 package android.support.v7.media; 17 18 import android.content.IntentFilter; 19 import android.os.Bundle; 20 21 import java.util.ArrayList; 22 import java.util.Arrays; 23 import java.util.Collection; 24 import java.util.Collections; 25 import java.util.List; 26 27 /** 28 * Describes the capabilities of routes that applications would like to discover and use. 29 * <p> 30 * This object is immutable once created using a {@link Builder} instance. 31 * </p> 32 * 33 * <h3>Example</h3> 34 * <pre> 35 * MediaRouteSelector selectorBuilder = new MediaRouteSelector.Builder() 36 * .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) 37 * .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) 38 * .build(); 39 * 40 * MediaRouter router = MediaRouter.getInstance(context); 41 * router.addCallback(selector, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); 42 * </pre> 43 */ 44 public final class MediaRouteSelector { 45 private static final String KEY_CONTROL_CATEGORIES = "controlCategories"; 46 47 private final Bundle mBundle; 48 private List<String> mControlCategories; 49 50 /** 51 * An empty media route selector that will not match any routes. 52 */ 53 public static final MediaRouteSelector EMPTY = new MediaRouteSelector(new Bundle(), null); 54 55 private MediaRouteSelector(Bundle bundle, List<String> controlCategories) { 56 mBundle = bundle; 57 mControlCategories = controlCategories; 58 } 59 60 /** 61 * Gets the list of {@link MediaControlIntent media control categories} in the selector. 62 * 63 * @return The list of categories. 64 */ 65 public List<String> getControlCategories() { 66 ensureControlCategories(); 67 return mControlCategories; 68 } 69 70 private void ensureControlCategories() { 71 if (mControlCategories == null) { 72 mControlCategories = mBundle.getStringArrayList(KEY_CONTROL_CATEGORIES); 73 if (mControlCategories == null || mControlCategories.isEmpty()) { 74 mControlCategories = Collections.<String>emptyList(); 75 } 76 } 77 } 78 79 /** 80 * Returns true if the selector contains the specified category. 81 * 82 * @param category The category to check. 83 * @return True if the category is present. 84 */ 85 public boolean hasControlCategory(String category) { 86 if (category != null) { 87 ensureControlCategories(); 88 final int categoryCount = mControlCategories.size(); 89 for (int i = 0; i < categoryCount; i++) { 90 if (mControlCategories.get(i).equals(category)) { 91 return true; 92 } 93 } 94 } 95 return false; 96 } 97 98 /** 99 * Returns true if the selector matches at least one of the specified control filters. 100 * 101 * @param filters The list of control filters to consider. 102 * @return True if a match is found. 103 */ 104 public boolean matchesControlFilters(List<IntentFilter> filters) { 105 if (filters != null) { 106 ensureControlCategories(); 107 final int categoryCount = mControlCategories.size(); 108 if (categoryCount != 0) { 109 final int filterCount = filters.size(); 110 for (int i = 0; i < filterCount; i++) { 111 final IntentFilter filter = filters.get(i); 112 if (filter != null) { 113 for (int j = 0; j < categoryCount; j++) { 114 if (filter.hasCategory(mControlCategories.get(j))) { 115 return true; 116 } 117 } 118 } 119 } 120 } 121 } 122 return false; 123 } 124 125 /** 126 * Returns true if this selector contains all of the capabilities described 127 * by the specified selector. 128 * 129 * @param selector The selector to be examined. 130 * @return True if this selector contains all of the capabilities described 131 * by the specified selector. 132 */ 133 public boolean contains(MediaRouteSelector selector) { 134 if (selector != null) { 135 ensureControlCategories(); 136 selector.ensureControlCategories(); 137 return mControlCategories.containsAll(selector.mControlCategories); 138 } 139 return false; 140 } 141 142 /** 143 * Returns true if the selector does not specify any capabilities. 144 */ 145 public boolean isEmpty() { 146 ensureControlCategories(); 147 return mControlCategories.isEmpty(); 148 } 149 150 /** 151 * Returns true if the selector has all of the required fields. 152 */ 153 public boolean isValid() { 154 ensureControlCategories(); 155 if (mControlCategories.contains(null)) { 156 return false; 157 } 158 return true; 159 } 160 161 @Override 162 public boolean equals(Object o) { 163 if (o instanceof MediaRouteSelector) { 164 MediaRouteSelector other = (MediaRouteSelector)o; 165 ensureControlCategories(); 166 other.ensureControlCategories(); 167 return mControlCategories.equals(other.mControlCategories); 168 } 169 return false; 170 } 171 172 @Override 173 public int hashCode() { 174 ensureControlCategories(); 175 return mControlCategories.hashCode(); 176 } 177 178 @Override 179 public String toString() { 180 StringBuilder result = new StringBuilder(); 181 result.append("MediaRouteSelector{ "); 182 result.append("controlCategories=").append( 183 Arrays.toString(getControlCategories().toArray())); 184 result.append(" }"); 185 return result.toString(); 186 } 187 188 /** 189 * Converts this object to a bundle for serialization. 190 * 191 * @return The contents of the object represented as a bundle. 192 */ 193 public Bundle asBundle() { 194 return mBundle; 195 } 196 197 /** 198 * Creates an instance from a bundle. 199 * 200 * @param bundle The bundle, or null if none. 201 * @return The new instance, or null if the bundle was null. 202 */ 203 public static MediaRouteSelector fromBundle(Bundle bundle) { 204 return bundle != null ? new MediaRouteSelector(bundle, null) : null; 205 } 206 207 /** 208 * Builder for {@link MediaRouteSelector media route selectors}. 209 */ 210 public static final class Builder { 211 private ArrayList<String> mControlCategories; 212 213 /** 214 * Creates an empty media route selector builder. 215 */ 216 public Builder() { 217 } 218 219 /** 220 * Creates a media route selector descriptor builder whose initial contents are 221 * copied from an existing selector. 222 */ 223 public Builder(MediaRouteSelector selector) { 224 if (selector == null) { 225 throw new IllegalArgumentException("selector must not be null"); 226 } 227 228 selector.ensureControlCategories(); 229 if (!selector.mControlCategories.isEmpty()) { 230 mControlCategories = new ArrayList<String>(selector.mControlCategories); 231 } 232 } 233 234 /** 235 * Adds a {@link MediaControlIntent media control category} to the builder. 236 * 237 * @param category The category to add to the set of desired capabilities, such as 238 * {@link MediaControlIntent#CATEGORY_LIVE_AUDIO}. 239 * @return The builder instance for chaining. 240 */ 241 public Builder addControlCategory(String category) { 242 if (category == null) { 243 throw new IllegalArgumentException("category must not be null"); 244 } 245 246 if (mControlCategories == null) { 247 mControlCategories = new ArrayList<String>(); 248 } 249 if (!mControlCategories.contains(category)) { 250 mControlCategories.add(category); 251 } 252 return this; 253 } 254 255 /** 256 * Adds a list of {@link MediaControlIntent media control categories} to the builder. 257 * 258 * @param categories The list categories to add to the set of desired capabilities, 259 * such as {@link MediaControlIntent#CATEGORY_LIVE_AUDIO}. 260 * @return The builder instance for chaining. 261 */ 262 public Builder addControlCategories(Collection<String> categories) { 263 if (categories == null) { 264 throw new IllegalArgumentException("categories must not be null"); 265 } 266 267 if (!categories.isEmpty()) { 268 for (String category : categories) { 269 addControlCategory(category); 270 } 271 } 272 return this; 273 } 274 275 /** 276 * Adds the contents of an existing media route selector to the builder. 277 * 278 * @param selector The media route selector whose contents are to be added. 279 * @return The builder instance for chaining. 280 */ 281 public Builder addSelector(MediaRouteSelector selector) { 282 if (selector == null) { 283 throw new IllegalArgumentException("selector must not be null"); 284 } 285 286 addControlCategories(selector.getControlCategories()); 287 return this; 288 } 289 290 /** 291 * Builds the {@link MediaRouteSelector media route selector}. 292 */ 293 public MediaRouteSelector build() { 294 if (mControlCategories == null) { 295 return EMPTY; 296 } 297 Bundle bundle = new Bundle(); 298 bundle.putStringArrayList(KEY_CONTROL_CATEGORIES, mControlCategories); 299 return new MediaRouteSelector(bundle, mControlCategories); 300 } 301 } 302 }