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