1fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu/* 2fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Copyright (C) 2017 The Android Open Source Project 3fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 4fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Licensed under the Apache License, Version 2.0 (the "License"); 5fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * you may not use this file except in compliance with the License. 6fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * You may obtain a copy of the License at 7fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 8fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * http://www.apache.org/licenses/LICENSE-2.0 9fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 10fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Unless required by applicable law or agreed to in writing, software 11fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * distributed under the License is distributed on an "AS IS" BASIS, 12fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * See the License for the specific language governing permissions and 14fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * limitations under the License. 15fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu */ 16fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 17fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiupackage com.android.server.wifi.hotspot2.anqp; 18fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 19fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport android.text.TextUtils; 20fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport android.util.Log; 21fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 22fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport com.android.internal.annotations.VisibleForTesting; 23fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport com.android.server.wifi.ByteBufferReader; 24fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 25fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.net.ProtocolException; 26fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.nio.BufferUnderflowException; 27fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.nio.ByteBuffer; 28fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.nio.ByteOrder; 29fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.nio.charset.StandardCharsets; 30fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.util.Arrays; 31fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiuimport java.util.Objects; 32fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 33fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu/** 34fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * The Icon Binary File vendor specific ANQP Element, 35fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Wi-Fi Alliance Hotspot 2.0 (Release 2) Technical Specification - Version 5.00, 36fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * section 4.10. 37fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 38fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Format: 39fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 40fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * | Status Code | Type Length | Type | Data Length | Data | 41fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 1 1 variable 2 variable 42fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 43fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu */ 44fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiupublic class HSIconFileElement extends ANQPElement { 45fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu private static final String TAG = "HSIconFileElement"; 46fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 47fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu /** 48fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Icon download status code. 49fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu */ 50fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public static final int STATUS_CODE_SUCCESS = 0; 51fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public static final int STATUS_CODE_FILE_NOT_FOUND = 1; 52fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public static final int STATUS_CODE_UNSPECIFIED_ERROR = 2; 53fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 54fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu private final int mStatusCode; 55fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu private final String mIconType; 56fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu private final byte[] mIconData; 57fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 58fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu @VisibleForTesting 59fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public HSIconFileElement(int statusCode, String iconType, byte[] iconData) { 60fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu super(Constants.ANQPElementType.HSIconFile); 61fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu mStatusCode = statusCode; 62fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu mIconType = iconType; 63fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu mIconData = iconData; 64fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 65fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 66fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu /** 67fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * Parse a HSIconFileElement from the given buffer. 68fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * 69fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * @param payload The buffer to read from 70fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * @return {@link HSIconFileElement} 71fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * @throws BufferUnderflowException 72fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu * @throws ProtocolException 73fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu */ 74fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public static HSIconFileElement parse(ByteBuffer payload) 75fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu throws ProtocolException { 76fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu // Parse status code. 77fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu int status = payload.get() & 0xFF; 78fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu if (status != STATUS_CODE_SUCCESS) { 79fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu // No more data if status code is not success. 80fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu Log.e(TAG, "Icon file download failed: " + status); 81fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return new HSIconFileElement(status, null, null); 82fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 83fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 84fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu // Parse icon type. 85fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu String iconType = 86fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu ByteBufferReader.readStringWithByteLength(payload, StandardCharsets.US_ASCII); 87fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 88fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu // Parse icon data. 89fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu int iconDataLength = 90fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu (int) ByteBufferReader.readInteger(payload, ByteOrder.LITTLE_ENDIAN, 2) & 0xFFFF; 91fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu byte[] iconData = new byte[iconDataLength]; 92fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu payload.get(iconData); 93fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 94fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return new HSIconFileElement(status, iconType, iconData); 95fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 96fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 97fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu @Override 98fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public boolean equals(Object thatObject) { 99fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu if (this == thatObject) { 100fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return true; 101fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 102fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu if (!(thatObject instanceof HSIconFileElement)) { 103fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return false; 104fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 105fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu HSIconFileElement that = (HSIconFileElement) thatObject; 106fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return mStatusCode == that.mStatusCode 107fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu && TextUtils.equals(mIconType, that.mIconType) 108fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu && Arrays.equals(mIconData, that.mIconData); 109fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 110fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 111fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu @Override 112fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public int hashCode() { 113fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return Objects.hash(mStatusCode, mIconType, Arrays.hashCode(mIconData)); 114fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 115fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu 116fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu @Override 117fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu public String toString() { 118fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu return "HSIconFileElement{" + "mStatusCode=" + mStatusCode 119fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu + "mIconType=" + mIconType + "}"; 120fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu } 121fa72bad238e1ac43501e0a2e27b50624e1431db7Peter Qiu} 122