1 /* 2 * Copyright 2019 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 android.media; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.text.TextUtils; 24 import android.util.ArrayMap; 25 26 import java.util.Arrays; 27 import java.util.Collection; 28 import java.util.Map; 29 import java.util.Objects; 30 31 /** 32 * Describes the state of a media router provider and the routes that it publishes. 33 * @hide 34 */ 35 public final class MediaRoute2ProviderInfo implements Parcelable { 36 @NonNull 37 public static final Creator<MediaRoute2ProviderInfo> CREATOR = 38 new Creator<MediaRoute2ProviderInfo>() { 39 @Override 40 public MediaRoute2ProviderInfo createFromParcel(Parcel in) { 41 return new MediaRoute2ProviderInfo(in); 42 } 43 @Override 44 public MediaRoute2ProviderInfo[] newArray(int size) { 45 return new MediaRoute2ProviderInfo[size]; 46 } 47 }; 48 49 @Nullable 50 final String mUniqueId; 51 @NonNull 52 final ArrayMap<String, MediaRoute2Info> mRoutes; 53 MediaRoute2ProviderInfo(@onNull Builder builder)54 MediaRoute2ProviderInfo(@NonNull Builder builder) { 55 Objects.requireNonNull(builder, "builder must not be null."); 56 57 mUniqueId = builder.mUniqueId; 58 mRoutes = builder.mRoutes; 59 } 60 MediaRoute2ProviderInfo(@onNull Parcel src)61 MediaRoute2ProviderInfo(@NonNull Parcel src) { 62 mUniqueId = src.readString(); 63 ArrayMap<String, MediaRoute2Info> routes = src.createTypedArrayMap(MediaRoute2Info.CREATOR); 64 mRoutes = (routes == null) ? ArrayMap.EMPTY : routes; 65 } 66 67 /** 68 * Returns true if the information of the provider and all of it's routes have all 69 * of the required fields. 70 * @hide 71 */ isValid()72 public boolean isValid() { 73 if (mUniqueId == null) { 74 return false; 75 } 76 final int count = mRoutes.size(); 77 for (int i = 0; i < count; i++) { 78 MediaRoute2Info route = mRoutes.valueAt(i); 79 if (route == null || !route.isValid()) { 80 return false; 81 } 82 } 83 return true; 84 } 85 86 /** 87 * @hide 88 */ 89 @Nullable getUniqueId()90 public String getUniqueId() { 91 return mUniqueId; 92 } 93 94 /** 95 * Gets the route for the given route id or null if no matching route exists. 96 * Please note that id should be original id. 97 * 98 * @see MediaRoute2Info#getOriginalId() 99 */ 100 @Nullable getRoute(@onNull String routeId)101 public MediaRoute2Info getRoute(@NonNull String routeId) { 102 return mRoutes.get(Objects.requireNonNull(routeId, "routeId must not be null")); 103 } 104 105 /** 106 * Gets the unmodifiable list of all routes that this provider has published. 107 */ 108 @NonNull getRoutes()109 public Collection<MediaRoute2Info> getRoutes() { 110 return mRoutes.values(); 111 } 112 113 @Override describeContents()114 public int describeContents() { 115 return 0; 116 } 117 118 @Override writeToParcel(@onNull Parcel dest, int flags)119 public void writeToParcel(@NonNull Parcel dest, int flags) { 120 dest.writeString(mUniqueId); 121 dest.writeTypedArrayMap(mRoutes, flags); 122 } 123 124 @Override toString()125 public String toString() { 126 StringBuilder result = new StringBuilder() 127 .append("MediaRouteProviderInfo { ") 128 .append("uniqueId=").append(mUniqueId) 129 .append(", routes=").append(Arrays.toString(getRoutes().toArray())) 130 .append(" }"); 131 return result.toString(); 132 } 133 134 /** 135 * Builder for {@link MediaRoute2ProviderInfo media route provider info}. 136 */ 137 public static final class Builder { 138 @NonNull 139 final ArrayMap<String, MediaRoute2Info> mRoutes; 140 String mUniqueId; 141 Builder()142 public Builder() { 143 mRoutes = new ArrayMap<>(); 144 } 145 Builder(@onNull MediaRoute2ProviderInfo descriptor)146 public Builder(@NonNull MediaRoute2ProviderInfo descriptor) { 147 Objects.requireNonNull(descriptor, "descriptor must not be null"); 148 149 mUniqueId = descriptor.mUniqueId; 150 mRoutes = new ArrayMap<>(descriptor.mRoutes); 151 } 152 153 /** 154 * Sets the package name and unique id of the provider info. 155 * <p> 156 * The unique id is automatically set by 157 * {@link com.android.server.media.MediaRouterService} and used to identify providers. 158 * The id set by {@link MediaRoute2ProviderService} will be ignored. 159 * </p> 160 * @hide 161 */ 162 @NonNull setUniqueId(@ullable String packageName, @Nullable String uniqueId)163 public Builder setUniqueId(@Nullable String packageName, @Nullable String uniqueId) { 164 if (TextUtils.equals(mUniqueId, uniqueId)) { 165 return this; 166 } 167 mUniqueId = uniqueId; 168 169 final ArrayMap<String, MediaRoute2Info> newRoutes = new ArrayMap<>(); 170 for (Map.Entry<String, MediaRoute2Info> entry : mRoutes.entrySet()) { 171 MediaRoute2Info routeWithProviderId = new MediaRoute2Info.Builder(entry.getValue()) 172 .setPackageName(packageName) 173 .setProviderId(mUniqueId) 174 .build(); 175 newRoutes.put(routeWithProviderId.getOriginalId(), routeWithProviderId); 176 } 177 178 mRoutes.clear(); 179 mRoutes.putAll(newRoutes); 180 return this; 181 } 182 183 /** 184 * Sets whether the provider provides system routes or not 185 */ 186 @NonNull setSystemRouteProvider(boolean isSystem)187 public Builder setSystemRouteProvider(boolean isSystem) { 188 int count = mRoutes.size(); 189 for (int i = 0; i < count; i++) { 190 MediaRoute2Info route = mRoutes.valueAt(i); 191 if (route.isSystemRoute() != isSystem) { 192 mRoutes.setValueAt(i, new MediaRoute2Info.Builder(route) 193 .setSystemRoute(isSystem) 194 .build()); 195 } 196 } 197 return this; 198 } 199 200 /** 201 * Adds a route to the provider 202 */ 203 @NonNull addRoute(@onNull MediaRoute2Info route)204 public Builder addRoute(@NonNull MediaRoute2Info route) { 205 Objects.requireNonNull(route, "route must not be null"); 206 207 if (mRoutes.containsKey(route.getOriginalId())) { 208 throw new IllegalArgumentException("A route with the same id is already added"); 209 } 210 if (mUniqueId != null) { 211 mRoutes.put(route.getOriginalId(), 212 new MediaRoute2Info.Builder(route).setProviderId(mUniqueId).build()); 213 } else { 214 mRoutes.put(route.getOriginalId(), route); 215 } 216 return this; 217 } 218 219 /** 220 * Adds a list of routes to the provider 221 */ 222 @NonNull addRoutes(@onNull Collection<MediaRoute2Info> routes)223 public Builder addRoutes(@NonNull Collection<MediaRoute2Info> routes) { 224 Objects.requireNonNull(routes, "routes must not be null"); 225 226 if (!routes.isEmpty()) { 227 for (MediaRoute2Info route : routes) { 228 addRoute(route); 229 } 230 } 231 return this; 232 } 233 234 /** 235 * Builds {@link MediaRoute2ProviderInfo media route provider info}. 236 */ 237 @NonNull build()238 public MediaRoute2ProviderInfo build() { 239 return new MediaRoute2ProviderInfo(this); 240 } 241 } 242 } 243