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.io.DataOutputStream; 22 import java.io.IOException; 23 import java.io.InputStream; 24 25 import javax.obex.ClientOperation; 26 import javax.obex.ClientSession; 27 import javax.obex.HeaderSet; 28 import javax.obex.ResponseCodes; 29 30 /** 31 * This is a base class for implementing AVRCP Controller Basic Image Profile (BIP) requests 32 */ 33 abstract class BipRequest { 34 private static final String TAG = "avrcpcontroller.BipRequest"; 35 private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); 36 37 // User defined OBEX header identifiers 38 protected static final byte HEADER_ID_IMG_HANDLE = 0x30; 39 protected static final byte HEADER_ID_IMG_DESCRIPTOR = 0x71; 40 41 // Request types 42 public static final int TYPE_GET_IMAGE_PROPERTIES = 0; 43 public static final int TYPE_GET_IMAGE = 1; 44 45 protected HeaderSet mHeaderSet; 46 protected ClientOperation mOperation = null; 47 protected int mResponseCode; 48 BipRequest()49 BipRequest() { 50 mHeaderSet = new HeaderSet(); 51 mResponseCode = -1; 52 } 53 54 /** 55 * A function that returns the type of the request. 56 * 57 * Used to determine type instead of using 'instanceof' 58 */ getType()59 public abstract int getType(); 60 61 /** 62 * A single point of entry for kicking off a AVRCP BIP request. 63 * 64 * Child classes are expected to implement this interface, filling in the details of the request 65 * (headers, operation type, error handling, etc). 66 */ execute(ClientSession session)67 public abstract void execute(ClientSession session) throws IOException; 68 69 /** 70 * A generica GET operation, providing overridable hooks to read response headers and content. 71 */ executeGet(ClientSession session)72 protected void executeGet(ClientSession session) throws IOException { 73 debug("Exeucting GET"); 74 setOperation(null); 75 try { 76 ClientOperation operation = (ClientOperation) session.get(mHeaderSet); 77 setOperation(operation); 78 operation.setGetFinalFlag(true); 79 operation.continueOperation(true, false); 80 readResponseHeaders(operation.getReceivedHeader()); 81 InputStream inputStream = operation.openInputStream(); 82 readResponse(inputStream); 83 inputStream.close(); 84 operation.close(); 85 mResponseCode = operation.getResponseCode(); 86 } catch (IOException e) { 87 mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 88 error("GET threw an exeception: " + e); 89 throw e; 90 } 91 debug("GET final response code is '" + mResponseCode + "'"); 92 } 93 94 /** 95 * A generica PUT operation, providing overridable hooks to read response headers. 96 */ executePut(ClientSession session, byte[] body)97 protected void executePut(ClientSession session, byte[] body) throws IOException { 98 debug("Exeucting PUT"); 99 setOperation(null); 100 mHeaderSet.setHeader(HeaderSet.LENGTH, Long.valueOf(body.length)); 101 try { 102 ClientOperation operation = (ClientOperation) session.put(mHeaderSet); 103 setOperation(operation); 104 DataOutputStream outputStream = mOperation.openDataOutputStream(); 105 outputStream.write(body); 106 outputStream.close(); 107 readResponseHeaders(operation.getReceivedHeader()); 108 operation.close(); 109 mResponseCode = operation.getResponseCode(); 110 } catch (IOException e) { 111 mResponseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 112 error("PUT threw an exeception: " + e); 113 throw e; 114 } 115 debug("PUT final response code is '" + mResponseCode + "'"); 116 } 117 118 /** 119 * Determine if the request was a success 120 * 121 * @return True if the request was successful, false otherwise 122 */ isSuccess()123 public final boolean isSuccess() { 124 return (mResponseCode == ResponseCodes.OBEX_HTTP_OK); 125 } 126 127 /** 128 * Get the actual response code associated with the request 129 * 130 * @return The response code as in integer 131 */ getResponseCode()132 public final int getResponseCode() { 133 return mResponseCode; 134 } 135 136 /** 137 * A callback for subclasses to add logic to make determinations against the content of the 138 * returned headers. 139 */ readResponseHeaders(HeaderSet headerset)140 protected void readResponseHeaders(HeaderSet headerset) { 141 /* nothing here by default */ 142 } 143 144 /** 145 * A callback for subclasses to add logic to make determinations against the content of the 146 * returned response body. 147 */ readResponse(InputStream stream)148 protected void readResponse(InputStream stream) throws IOException { 149 /* nothing here by default */ 150 } 151 getOperation()152 private synchronized ClientOperation getOperation() { 153 return mOperation; 154 } 155 setOperation(ClientOperation operation)156 private synchronized void setOperation(ClientOperation operation) { 157 mOperation = operation; 158 } 159 160 @Override toString()161 public String toString() { 162 return TAG + " (type: " + getType() + ", mResponseCode: " + mResponseCode + ")"; 163 } 164 165 /** 166 * Print to debug if debug is enabled for this class 167 */ debug(String msg)168 protected void debug(String msg) { 169 if (DBG) { 170 Log.d(TAG, msg); 171 } 172 } 173 174 /** 175 * Print to warn 176 */ warn(String msg)177 protected void warn(String msg) { 178 Log.w(TAG, msg); 179 } 180 181 /** 182 * Print to error 183 */ error(String msg)184 protected void error(String msg) { 185 Log.e(TAG, msg); 186 } 187 } 188