MediaRouteSelector.java revision f03da4a9e6cc02251c2f804eb6f25da61821d6a7
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 */
16package android.support.v7.media;
17
18import android.content.IntentFilter;
19import android.os.Bundle;
20
21import java.util.ArrayList;
22import java.util.Arrays;
23import java.util.Collection;
24import java.util.Collections;
25import 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 */
44public 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}