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.bluetooth.avrcpcontroller; 18 19 import android.util.Log; 20 21 import java.util.Objects; 22 23 /** 24 * Describes a single native or variant format available for an image, coming from a 25 * BipImageProperties object. 26 * 27 * <p>This is not an object by specification, per say. It abstracts all the various native and 28 * variant formats available in a given set of image properties. 29 * 30 * <p>This BipImageFormat can be used to choose a specific BipImageDescriptor when downloading an 31 * image 32 * 33 * <p>Examples: <native encoding="JPEG" pixel="1280*1024” size="1048576"/> <variant encoding="JPEG" 34 * pixel="640*480"/> <variant encoding="JPEG" pixel="160*120"/> <variant encoding="GIF" 35 * pixel="80*60-640*480"/> 36 */ 37 public class BipImageFormat { 38 private static final String TAG = "avrcpcontroller.BipImageFormat"; 39 40 public static final int FORMAT_NATIVE = 0; 41 public static final int FORMAT_VARIANT = 1; 42 43 /** Create a native BipImageFormat from the given string fields */ parseNative(String encoding, String pixel, String size)44 public static BipImageFormat parseNative(String encoding, String pixel, String size) { 45 return new BipImageFormat(BipImageFormat.FORMAT_NATIVE, encoding, pixel, size, null, null); 46 } 47 48 /** Create a variant BipImageFormat from the given string fields */ parseVariant( String encoding, String pixel, String maxSize, String transformation)49 public static BipImageFormat parseVariant( 50 String encoding, String pixel, String maxSize, String transformation) { 51 return new BipImageFormat( 52 BipImageFormat.FORMAT_VARIANT, encoding, pixel, null, maxSize, transformation); 53 } 54 55 /** Create a native BipImageFormat from the given parameters */ createNative(BipEncoding encoding, BipPixel pixel, int size)56 public static BipImageFormat createNative(BipEncoding encoding, BipPixel pixel, int size) { 57 return new BipImageFormat(BipImageFormat.FORMAT_NATIVE, encoding, pixel, size, -1, null); 58 } 59 60 /** Create a variant BipImageFormat from the given parameters */ createVariant( BipEncoding encoding, BipPixel pixel, int maxSize, BipTransformation transformation)61 public static BipImageFormat createVariant( 62 BipEncoding encoding, BipPixel pixel, int maxSize, BipTransformation transformation) { 63 return new BipImageFormat( 64 BipImageFormat.FORMAT_VARIANT, encoding, pixel, -1, maxSize, transformation); 65 } 66 67 /** The 'flavor' of this image format, from the format constants above. */ 68 private final int mFormatType; 69 70 /** The encoding method in which this image is available, required by the specification */ 71 private final BipEncoding mEncoding; 72 73 /** 74 * The pixel size or range of pixel sizes in which the image is available, required by the 75 * specification 76 */ 77 private final BipPixel mPixel; 78 79 /** 80 * The list of supported image transformation methods, any of: - 'stretch' : Image server is 81 * capable of stretching the image to fit a space - 'fill' : Image server is capable of filling 82 * the image padding data to fit a space - 'crop' : Image server is capable of cropping the 83 * image down to fit a space 84 * 85 * <p>Used by the variant type only 86 */ 87 private final BipTransformation mTransformation; 88 89 /** 90 * Size in bytes of the image. 91 * 92 * <p>Used by the native type only 93 */ 94 private final int mSize; 95 96 /** 97 * The estimated maximum size of an image after a transformation is performed. 98 * 99 * <p>Used by the variant type only 100 */ 101 private final int mMaxSize; 102 BipImageFormat( int type, BipEncoding encoding, BipPixel pixel, int size, int maxSize, BipTransformation transformation)103 private BipImageFormat( 104 int type, 105 BipEncoding encoding, 106 BipPixel pixel, 107 int size, 108 int maxSize, 109 BipTransformation transformation) { 110 mFormatType = type; 111 mEncoding = Objects.requireNonNull(encoding, "Encoding cannot be null"); 112 mPixel = Objects.requireNonNull(pixel, "Pixel cannot be null"); 113 mTransformation = transformation; 114 mSize = size; 115 mMaxSize = maxSize; 116 } 117 BipImageFormat( int type, String encoding, String pixel, String size, String maxSize, String transformation)118 private BipImageFormat( 119 int type, 120 String encoding, 121 String pixel, 122 String size, 123 String maxSize, 124 String transformation) { 125 mFormatType = type; 126 mEncoding = new BipEncoding(encoding); 127 mPixel = new BipPixel(pixel); 128 mTransformation = new BipTransformation(transformation); 129 mSize = parseInt(size); 130 mMaxSize = parseInt(maxSize); 131 } 132 parseInt(String s)133 private static int parseInt(String s) { 134 if (s == null) return -1; 135 try { 136 return Integer.parseInt(s); 137 } catch (NumberFormatException e) { 138 error("Failed to parse '" + s + "'"); 139 } 140 return -1; 141 } 142 getType()143 public int getType() { 144 return mFormatType; 145 } 146 getEncoding()147 public BipEncoding getEncoding() { 148 return mEncoding; 149 } 150 getPixel()151 public BipPixel getPixel() { 152 return mPixel; 153 } 154 getTransformation()155 public BipTransformation getTransformation() { 156 return mTransformation; 157 } 158 getSize()159 public int getSize() { 160 return mSize; 161 } 162 getMaxSize()163 public int getMaxSize() { 164 return mMaxSize; 165 } 166 167 @Override equals(Object o)168 public boolean equals(Object o) { 169 if (o == this) return true; 170 if (!(o instanceof BipImageFormat)) return false; 171 172 BipImageFormat f = (BipImageFormat) o; 173 return f.getType() == getType() 174 && f.getEncoding() == getEncoding() 175 && f.getPixel() == getPixel() 176 && f.getTransformation() == getTransformation() 177 && f.getSize() == getSize() 178 && f.getMaxSize() == getMaxSize(); 179 } 180 181 @Override toString()182 public String toString() { 183 if (mEncoding == null 184 || mEncoding.getType() == BipEncoding.UNKNOWN 185 || mPixel == null 186 || mPixel.getType() == BipPixel.TYPE_UNKNOWN) { 187 error( 188 "Missing required fields [ " 189 + (mEncoding == null ? "encoding " : "") 190 + (mPixel == null ? "pixel " : "")); 191 return null; 192 } 193 194 StringBuilder sb = new StringBuilder(); 195 switch (mFormatType) { 196 case FORMAT_NATIVE: 197 sb.append("<native"); 198 sb.append(" encoding=\"" + mEncoding.toString() + "\""); 199 sb.append(" pixel=\"" + mPixel.toString() + "\""); 200 if (mSize > -1) { 201 sb.append(" size=\"" + mSize + "\""); 202 } 203 sb.append(" />"); 204 return sb.toString(); 205 case FORMAT_VARIANT: 206 sb.append("<variant"); 207 sb.append(" encoding=\"" + mEncoding.toString() + "\""); 208 sb.append(" pixel=\"" + mPixel.toString() + "\""); 209 if (mTransformation != null && mTransformation.supportsAny()) { 210 sb.append(" transformation=\"" + mTransformation.toString() + "\""); 211 } 212 if (mSize > -1) { 213 sb.append(" size=\"" + mSize + "\""); 214 } 215 if (mMaxSize > -1) { 216 sb.append(" maxsize=\"" + mMaxSize + "\""); 217 } 218 sb.append(" />"); 219 return sb.toString(); 220 default: 221 error("Unsupported format type '" + mFormatType + "'"); 222 } 223 return null; 224 } 225 error(String msg)226 private static void error(String msg) { 227 Log.e(TAG, msg); 228 } 229 } 230