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.os.Bundle;
19
20import java.util.ArrayList;
21import java.util.Arrays;
22import java.util.Collection;
23import java.util.Collections;
24import java.util.List;
25
26/**
27 * Describes the state of a media route provider and the routes that it publishes.
28 * <p>
29 * This object is immutable once created using a {@link Builder} instance.
30 * </p>
31 */
32public final class MediaRouteProviderDescriptor {
33    private static final String KEY_ROUTES = "routes";
34
35    private final Bundle mBundle;
36    private List<MediaRouteDescriptor> mRoutes;
37
38    private MediaRouteProviderDescriptor(Bundle bundle, List<MediaRouteDescriptor> routes) {
39        mBundle = bundle;
40        mRoutes = routes;
41    }
42
43    /**
44     * Gets the list of all routes that this provider has published.
45     */
46    public List<MediaRouteDescriptor> getRoutes() {
47        ensureRoutes();
48        return mRoutes;
49    }
50
51    private void ensureRoutes() {
52        if (mRoutes == null) {
53            ArrayList<Bundle> routeBundles = mBundle.<Bundle>getParcelableArrayList(KEY_ROUTES);
54            if (routeBundles == null || routeBundles.isEmpty()) {
55                mRoutes = Collections.<MediaRouteDescriptor>emptyList();
56            } else {
57                final int count = routeBundles.size();
58                mRoutes = new ArrayList<MediaRouteDescriptor>(count);
59                for (int i = 0; i < count; i++) {
60                    mRoutes.add(MediaRouteDescriptor.fromBundle(routeBundles.get(i)));
61                }
62            }
63        }
64    }
65
66    /**
67     * Returns true if the route provider descriptor and all of the routes that
68     * it contains have all of the required fields.
69     * <p>
70     * This verification is deep.  If the provider descriptor is known to be
71     * valid then it is not necessary to call {@link #isValid} on each of its routes.
72     * </p>
73     */
74    public boolean isValid() {
75        ensureRoutes();
76        final int routeCount = mRoutes.size();
77        for (int i = 0; i < routeCount; i++) {
78            MediaRouteDescriptor route = mRoutes.get(i);
79            if (route == null || !route.isValid()) {
80                return false;
81            }
82        }
83        return true;
84    }
85
86    @Override
87    public String toString() {
88        StringBuilder result = new StringBuilder();
89        result.append("MediaRouteProviderDescriptor{ ");
90        result.append("routes=").append(
91                Arrays.toString(getRoutes().toArray()));
92        result.append(", isValid=").append(isValid());
93        result.append(" }");
94        return result.toString();
95    }
96
97    /**
98     * Converts this object to a bundle for serialization.
99     *
100     * @return The contents of the object represented as a bundle.
101     */
102    public Bundle asBundle() {
103        return mBundle;
104    }
105
106    /**
107     * Creates an instance from a bundle.
108     *
109     * @param bundle The bundle, or null if none.
110     * @return The new instance, or null if the bundle was null.
111     */
112    public static MediaRouteProviderDescriptor fromBundle(Bundle bundle) {
113        return bundle != null ? new MediaRouteProviderDescriptor(bundle, null) : null;
114    }
115
116    /**
117     * Builder for {@link MediaRouteProviderDescriptor media route provider descriptors}.
118     */
119    public static final class Builder {
120        private final Bundle mBundle;
121        private ArrayList<MediaRouteDescriptor> mRoutes;
122
123        /**
124         * Creates an empty media route provider descriptor builder.
125         */
126        public Builder() {
127            mBundle = new Bundle();
128        }
129
130        /**
131         * Creates a media route provider descriptor builder whose initial contents are
132         * copied from an existing descriptor.
133         */
134        public Builder(MediaRouteProviderDescriptor descriptor) {
135            if (descriptor == null) {
136                throw new IllegalArgumentException("descriptor must not be null");
137            }
138
139            mBundle = new Bundle(descriptor.mBundle);
140
141            descriptor.ensureRoutes();
142            if (!descriptor.mRoutes.isEmpty()) {
143                mRoutes = new ArrayList<MediaRouteDescriptor>(descriptor.mRoutes);
144            }
145        }
146
147        /**
148         * Adds a route.
149         */
150        public Builder addRoute(MediaRouteDescriptor route) {
151            if (route == null) {
152                throw new IllegalArgumentException("route must not be null");
153            }
154
155            if (mRoutes == null) {
156                mRoutes = new ArrayList<MediaRouteDescriptor>();
157            } else if (mRoutes.contains(route)) {
158                throw new IllegalArgumentException("route descriptor already added");
159            }
160            mRoutes.add(route);
161            return this;
162        }
163
164        /**
165         * Adds a list of routes.
166         */
167        public Builder addRoutes(Collection<MediaRouteDescriptor> routes) {
168            if (routes == null) {
169                throw new IllegalArgumentException("routes must not be null");
170            }
171
172            if (!routes.isEmpty()) {
173                for (MediaRouteDescriptor route : routes) {
174                    addRoute(route);
175                }
176            }
177            return this;
178        }
179
180        /**
181         * Sets the list of routes.
182         */
183        Builder setRoutes(Collection<MediaRouteDescriptor> routes) {
184            if (routes == null || routes.isEmpty()) {
185                mRoutes = null;
186                mBundle.remove(KEY_ROUTES);
187            } else {
188                mRoutes = new ArrayList<>(routes);
189            }
190            return this;
191        }
192
193        /**
194         * Builds the {@link MediaRouteProviderDescriptor media route provider descriptor}.
195         */
196        public MediaRouteProviderDescriptor build() {
197            if (mRoutes != null) {
198                final int count = mRoutes.size();
199                ArrayList<Bundle> routeBundles = new ArrayList<Bundle>(count);
200                for (int i = 0; i < count; i++) {
201                    routeBundles.add(mRoutes.get(i).asBundle());
202                }
203                mBundle.putParcelableArrayList(KEY_ROUTES, routeBundles);
204            }
205            return new MediaRouteProviderDescriptor(mBundle, mRoutes);
206        }
207    }
208}