1 /* 2 * Copyright (C) 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 com.android.providers.media.util; 18 19 import android.media.ExifInterface; 20 import android.text.TextUtils; 21 22 import androidx.annotation.NonNull; 23 import androidx.annotation.Nullable; 24 25 /** 26 * Parser for Extensible Metadata Platform (XMP) metadata. Designed to mirror 27 * ergonomics of {@link ExifInterface}. 28 * <p> 29 * Since values can be repeated multiple times within the same XMP data, this 30 * parser prefers the first valid definition of a specific value, and it ignores 31 * any subsequent attempts to redefine that value. 32 */ 33 public class XmpInterface { 34 private final String mFormat; 35 private final String mDocumentId; 36 private final String mInstanceId; 37 private final String mOriginalDocumentId; 38 39 private final @NonNull byte[] mRedactedXmp; 40 XmpInterface(String format, String documentId, String instanceId, String originalDocumentId, @NonNull byte[] redactedXmp)41 private XmpInterface(String format, String documentId, 42 String instanceId, String originalDocumentId, @NonNull byte[] redactedXmp) { 43 mFormat = format; 44 mDocumentId = documentId; 45 mInstanceId = instanceId; 46 mOriginalDocumentId = originalDocumentId; 47 mRedactedXmp = redactedXmp; 48 } 49 50 static class Builder { 51 String mFormat; 52 String mDocumentId; 53 String mInstanceId; 54 String mOriginalDocumentId; 55 byte[] mRedactedXmp; 56 format(String format)57 Builder format(String format) { 58 mFormat = maybeOverride(mFormat, format); 59 return this; 60 } 61 documentId(String documentId)62 Builder documentId(String documentId) { 63 mDocumentId = maybeOverride(mDocumentId, documentId); 64 return this; 65 } 66 instanceId(String instanceId)67 Builder instanceId(String instanceId) { 68 mInstanceId = maybeOverride(mInstanceId, instanceId); 69 return this; 70 } 71 originalDocumentId(String originalDocumentId)72 Builder originalDocumentId(String originalDocumentId) { 73 mOriginalDocumentId = maybeOverride(mOriginalDocumentId, originalDocumentId); 74 return this; 75 } 76 Builder(byte[] redactedXmp)77 Builder(byte[] redactedXmp) { 78 mRedactedXmp = redactedXmp; 79 } 80 build()81 XmpInterface build() { 82 return new XmpInterface(mFormat, mDocumentId, mInstanceId, mOriginalDocumentId, 83 mRedactedXmp); 84 } 85 maybeOverride(@ullable String existing, @Nullable String current)86 private static @Nullable String maybeOverride(@Nullable String existing, 87 @Nullable String current) { 88 if (!TextUtils.isEmpty(existing)) { 89 // If already defined, first definition always wins 90 return existing; 91 } else if (!TextUtils.isEmpty(current)) { 92 // If current defined, it wins 93 return current; 94 } else { 95 // Otherwise, null wins to prevent weird empty strings 96 return null; 97 } 98 } 99 } 100 getFormat()101 public @Nullable String getFormat() { 102 return mFormat; 103 } 104 getDocumentId()105 public @Nullable String getDocumentId() { 106 return mDocumentId; 107 } 108 getInstanceId()109 public @Nullable String getInstanceId() { 110 return mInstanceId; 111 } 112 getOriginalDocumentId()113 public @Nullable String getOriginalDocumentId() { 114 return mOriginalDocumentId; 115 } 116 getRedactedXmp()117 public @NonNull byte[] getRedactedXmp() { 118 return mRedactedXmp; 119 } 120 } 121