1 /* 2 * Copyright (C) 2021 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.tv; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.StringDef; 22 import android.os.Parcel; 23 import android.os.ParcelFileDescriptor; 24 import android.os.Parcelable; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.util.ArrayList; 29 import java.util.List; 30 31 /** 32 * A response for DSM-CC from broadcast signal. 33 */ 34 public final class DsmccResponse extends BroadcastInfoResponse implements Parcelable { 35 private static final @TvInputManager.BroadcastInfoType int RESPONSE_TYPE = 36 TvInputManager.BROADCAST_INFO_TYPE_DSMCC; 37 38 /** @hide */ 39 @Retention(RetentionPolicy.SOURCE) 40 @StringDef(prefix = "BIOP_MESSAGE_TYPE_", value = { 41 BIOP_MESSAGE_TYPE_DIRECTORY, 42 BIOP_MESSAGE_TYPE_FILE, 43 BIOP_MESSAGE_TYPE_STREAM, 44 BIOP_MESSAGE_TYPE_SERVICE_GATEWAY, 45 46 }) 47 public @interface BiopMessageType {} 48 49 /** Broadcast Inter-ORB Protocol (BIOP) message types */ 50 /** BIOP directory message */ 51 public static final String BIOP_MESSAGE_TYPE_DIRECTORY = "directory"; 52 /** BIOP file message */ 53 public static final String BIOP_MESSAGE_TYPE_FILE = "file"; 54 /** BIOP stream message */ 55 public static final String BIOP_MESSAGE_TYPE_STREAM = "stream"; 56 /** BIOP service gateway message */ 57 public static final String BIOP_MESSAGE_TYPE_SERVICE_GATEWAY = "service_gateway"; 58 59 public static final @NonNull Parcelable.Creator<DsmccResponse> CREATOR = 60 new Parcelable.Creator<DsmccResponse>() { 61 @Override 62 public DsmccResponse createFromParcel(Parcel source) { 63 source.readInt(); 64 return createFromParcelBody(source); 65 } 66 67 @Override 68 public DsmccResponse[] newArray(int size) { 69 return new DsmccResponse[size]; 70 } 71 }; 72 73 private final @BiopMessageType String mBiopMessageType; 74 private final ParcelFileDescriptor mFileDescriptor; 75 private final List<String> mChildList; 76 private final int[] mEventIds; 77 private final String[] mEventNames; 78 createFromParcelBody(Parcel in)79 static DsmccResponse createFromParcelBody(Parcel in) { 80 return new DsmccResponse(in); 81 } 82 83 /** 84 * Constructs a BIOP file message response. 85 */ DsmccResponse(int requestId, int sequence, @ResponseResult int responseResult, @Nullable ParcelFileDescriptor file)86 public DsmccResponse(int requestId, int sequence, @ResponseResult int responseResult, 87 @Nullable ParcelFileDescriptor file) { 88 super(RESPONSE_TYPE, requestId, sequence, responseResult); 89 mBiopMessageType = BIOP_MESSAGE_TYPE_FILE; 90 mFileDescriptor = file; 91 mChildList = null; 92 mEventIds = null; 93 mEventNames = null; 94 } 95 96 /** 97 * Constructs a BIOP service gateway or directory message response. 98 */ DsmccResponse(int requestId, int sequence, @ResponseResult int responseResult, boolean isServiceGateway, @Nullable List<String> childList)99 public DsmccResponse(int requestId, int sequence, @ResponseResult int responseResult, 100 boolean isServiceGateway, @Nullable List<String> childList) { 101 super(RESPONSE_TYPE, requestId, sequence, responseResult); 102 if (isServiceGateway) { 103 mBiopMessageType = BIOP_MESSAGE_TYPE_SERVICE_GATEWAY; 104 } else { 105 mBiopMessageType = BIOP_MESSAGE_TYPE_DIRECTORY; 106 } 107 mFileDescriptor = null; 108 mChildList = childList; 109 mEventIds = null; 110 mEventNames = null; 111 } 112 113 /** 114 * Constructs a BIOP stream message response. 115 * 116 * <p>The current stream message response does not support other stream messages types than 117 * stream event message type. 118 */ DsmccResponse(int requestId, int sequence, @ResponseResult int responseResult, @Nullable int[] eventIds, @Nullable String[] eventNames)119 public DsmccResponse(int requestId, int sequence, @ResponseResult int responseResult, 120 @Nullable int[] eventIds, @Nullable String[] eventNames) { 121 super(RESPONSE_TYPE, requestId, sequence, responseResult); 122 mBiopMessageType = BIOP_MESSAGE_TYPE_STREAM; 123 mFileDescriptor = null; 124 mChildList = null; 125 if (!((eventIds != null && eventNames != null && eventIds.length == eventNames.length) 126 || (eventIds == null && eventNames == null))) { 127 throw new IllegalStateException("The size of eventIds and eventNames must be equal"); 128 } 129 mEventIds = eventIds; 130 mEventNames = eventNames; 131 } 132 DsmccResponse(@onNull Parcel source)133 private DsmccResponse(@NonNull Parcel source) { 134 super(RESPONSE_TYPE, source); 135 136 mBiopMessageType = source.readString(); 137 switch (mBiopMessageType) { 138 case BIOP_MESSAGE_TYPE_SERVICE_GATEWAY: 139 case BIOP_MESSAGE_TYPE_DIRECTORY: 140 int childNum = source.readInt(); 141 if (childNum > 0) { 142 mChildList = new ArrayList<>(); 143 for (int i = 0; i < childNum; i++) { 144 mChildList.add(source.readString()); 145 } 146 } else 147 mChildList = null; 148 mFileDescriptor = null; 149 mEventIds = null; 150 mEventNames = null; 151 break; 152 case BIOP_MESSAGE_TYPE_FILE: 153 mFileDescriptor = source.readFileDescriptor(); 154 mChildList = null; 155 mEventIds = null; 156 mEventNames = null; 157 break; 158 case BIOP_MESSAGE_TYPE_STREAM: 159 int eventNum = source.readInt(); 160 if (eventNum > 0) { 161 mEventIds = new int[eventNum]; 162 mEventNames = new String[eventNum]; 163 for (int i = 0; i < eventNum; i++) { 164 mEventIds[i] = source.readInt(); 165 mEventNames[i] = source.readString(); 166 } 167 } else { 168 mEventIds = null; 169 mEventNames = null; 170 } 171 mChildList = null; 172 mFileDescriptor = null; 173 break; 174 default: 175 throw new IllegalStateException("unexpected BIOP message type"); 176 } 177 } 178 179 /** 180 * Returns the BIOP message type. 181 */ 182 @NonNull getBiopMessageType()183 public @BiopMessageType String getBiopMessageType() { 184 return mBiopMessageType; 185 } 186 187 /** 188 * Returns the file descriptor for a given file message response. 189 */ 190 @NonNull getFile()191 public ParcelFileDescriptor getFile() { 192 if (!mBiopMessageType.equals(BIOP_MESSAGE_TYPE_FILE)) { 193 throw new IllegalStateException("Not file object"); 194 } 195 return mFileDescriptor; 196 } 197 198 /** 199 * Returns a list of subobject names for the given service gateway or directory message 200 * response. 201 */ 202 @NonNull getChildList()203 public List<String> getChildList() { 204 if (!mBiopMessageType.equals(BIOP_MESSAGE_TYPE_DIRECTORY) 205 && !mBiopMessageType.equals(BIOP_MESSAGE_TYPE_SERVICE_GATEWAY)) { 206 throw new IllegalStateException("Not directory object"); 207 } 208 return mChildList != null ? new ArrayList<String>(mChildList) : new ArrayList<String>(); 209 } 210 211 /** 212 * Returns all event IDs carried in a given stream message response. 213 */ 214 @NonNull getStreamEventIds()215 public int[] getStreamEventIds() { 216 if (!mBiopMessageType.equals(BIOP_MESSAGE_TYPE_STREAM)) { 217 throw new IllegalStateException("Not stream event object"); 218 } 219 return mEventIds != null ? mEventIds : new int[0]; 220 } 221 222 /** 223 * Returns all event names carried in a given stream message response. 224 */ 225 @NonNull getStreamEventNames()226 public String[] getStreamEventNames() { 227 if (!mBiopMessageType.equals(BIOP_MESSAGE_TYPE_STREAM)) { 228 throw new IllegalStateException("Not stream event object"); 229 } 230 return mEventNames != null ? mEventNames : new String[0]; 231 } 232 233 @Override describeContents()234 public int describeContents() { 235 return 0; 236 } 237 238 @Override writeToParcel(@onNull Parcel dest, int flags)239 public void writeToParcel(@NonNull Parcel dest, int flags) { 240 super.writeToParcel(dest, flags); 241 dest.writeString(mBiopMessageType); 242 switch (mBiopMessageType) { 243 case BIOP_MESSAGE_TYPE_SERVICE_GATEWAY: 244 case BIOP_MESSAGE_TYPE_DIRECTORY: 245 if (mChildList != null && mChildList.size() > 0) { 246 dest.writeInt(mChildList.size()); 247 for (String child : mChildList) { 248 dest.writeString(child); 249 } 250 } else 251 dest.writeInt(0); 252 break; 253 case BIOP_MESSAGE_TYPE_FILE: 254 dest.writeFileDescriptor(mFileDescriptor.getFileDescriptor()); 255 break; 256 case BIOP_MESSAGE_TYPE_STREAM: 257 if (mEventIds != null && mEventIds.length > 0) { 258 dest.writeInt(mEventIds.length); 259 for (int i = 0; i < mEventIds.length; i++) { 260 dest.writeInt(mEventIds[i]); 261 dest.writeString(mEventNames[i]); 262 } 263 } else 264 dest.writeInt(0); 265 break; 266 default: 267 throw new IllegalStateException("unexpected BIOP message type"); 268 } 269 } 270 } 271