19fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu/*
29fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * Copyright (C) 2017 The Android Open Source Project
39fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu *
49fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * Licensed under the Apache License, Version 2.0 (the "License");
59fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * you may not use this file except in compliance with the License.
69fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * You may obtain a copy of the License at
79fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu *
89fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu *      http://www.apache.org/licenses/LICENSE-2.0
99fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu *
109fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * Unless required by applicable law or agreed to in writing, software
119fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * distributed under the License is distributed on an "AS IS" BASIS,
129fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * See the License for the specific language governing permissions and
149fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * limitations under the License.
159fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu */
169fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
179fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiupackage com.android.server.wifi.hotspot2.anqp;
189fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
199fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport android.net.Uri;
209fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
219fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport java.io.ByteArrayOutputStream;
229fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport java.io.IOException;
239fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport java.nio.charset.StandardCharsets;
249fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport java.util.Arrays;
259fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport java.util.List;
269fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiuimport java.util.Locale;
279fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
289fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu/**
299fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu * Utility class containing test data and object for {@link OsuProviderInfo}.
309fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu */
319fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiupublic class OsuProviderInfoTestUtil {
329fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    // Test data
339fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static final List<I18Name> TEST_FRIENDLY_NAMES =
349fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            Arrays.asList(new I18Name("en", Locale.forLanguageTag("en"), "FriendlyName"));
359fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static final String TEST_SERVER_URI = "test.server.com";
369fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static final List<Integer> TEST_METHOD_LIST = Arrays.asList(0, 1);
379fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static final List<IconInfo> TEST_ICON_INFO_LIST =
389fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            Arrays.asList(IconInfoTestUtil.TEST_ICON_INFO);
399fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static final String TEST_NAI = "network_access@test.com";
409fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static final List<I18Name> TEST_SERVICE_DESCRIPTIONS =
419fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            Arrays.asList(new I18Name("en", Locale.forLanguageTag("en"), "Test Service"));
429fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
439fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
449fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * {@link IconInfo} object with pre-defined test data.
459fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
469fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    public static final OsuProviderInfo TEST_OSU_PROVIDER_INFO =
479fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            new OsuProviderInfo(TEST_FRIENDLY_NAMES, Uri.parse(TEST_SERVER_URI), TEST_METHOD_LIST,
489fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu                    TEST_ICON_INFO_LIST, TEST_NAI, TEST_SERVICE_DESCRIPTIONS);
499fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
509fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
519fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Raw bytes of icon info with pre-defined test data.
529fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
539fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    public static final byte[] TEST_OSU_PROVIDER_INFO_RAW_BYTES = getTestData();
549fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
559fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    public static final byte[] TEST_OSU_PROVIDER_INFO_RAW_BYTES_WITH_INVALID_LENGTH =
569fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            getTestDataWithInvalidLength();
579fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
589fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
599fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Generate and return the raw data based on pre-defined test data.
609fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     *
619fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @return byte[]
629fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
639fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static byte[] getTestData() {
649fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        try {
659fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            ByteArrayOutputStream out = new ByteArrayOutputStream();
669fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            byte[] payload = getTestPayload();
679fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            writeShortLE(out, payload.length);
689fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            out.write(payload);
699fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            return out.toByteArray();
709fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        } catch (Exception e) {
719fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            return null;
729fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        }
739fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
749fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
759fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
769fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Generate and return the raw data based on pre-defined test data.
779fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     *
789fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @return byte[]
799fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
809fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static byte[] getTestDataWithInvalidLength() {
819fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        try {
829fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            ByteArrayOutputStream out = new ByteArrayOutputStream();
839fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            byte[] payload = getTestPayload();
849fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            // Set length to less than the minimum required.
859fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            writeShortLE(out, OsuProviderInfo.MINIMUM_LENGTH - 1);
869fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            out.write(payload);
879fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            return out.toByteArray();
889fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        } catch (Exception e) {
899fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            return null;
909fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        }
919fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
929fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
939fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
949fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Generate and return the payload containing OSU provider test data, excluding the length
959fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * field.
969fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     *
979fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @return byte[]
989fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @throws IOException
999fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
1009fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static byte[] getTestPayload() throws IOException {
1019fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        ByteArrayOutputStream out = new ByteArrayOutputStream();
1029fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1039fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        // Write friendly name list.
1049fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        byte[] friendlyNamesData = getI18NameListData(TEST_FRIENDLY_NAMES);
1059fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        writeShortLE(out, friendlyNamesData.length);
1069fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(friendlyNamesData);
1079fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1089fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        // Write server URI.
1099fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        writeByteArrayWithLength(out, TEST_SERVER_URI.getBytes(StandardCharsets.UTF_8));
1109fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1119fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        // Write method list.
1129fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write((byte) TEST_METHOD_LIST.size());
1139fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        for (Integer method : TEST_METHOD_LIST) {
1149fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            out.write((byte) method.intValue());
1159fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        }
1169fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1179fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        // Write icon info list.
1189fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        writeShortLE(out, IconInfoTestUtil.TEST_ICON_INFO_RAW_BYTES.length);
1199fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(IconInfoTestUtil.TEST_ICON_INFO_RAW_BYTES);
1209fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1219fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        // Write NAI.
1229fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        writeByteArrayWithLength(out, TEST_NAI.getBytes(StandardCharsets.UTF_8));
1239fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1249fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        // Write service descriptions.
1259fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        byte[] serviceDescriptionsData = getI18NameListData(TEST_SERVICE_DESCRIPTIONS);
1269fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        writeShortLE(out, serviceDescriptionsData.length);
1279fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(serviceDescriptionsData);
1289fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1299fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        return out.toByteArray();
1309fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
1319fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1329fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static byte[] getI18NameListData(List<I18Name> nameList) throws IOException {
1339fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        ByteArrayOutputStream out = new ByteArrayOutputStream();
1349fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        for (I18Name name : nameList) {
1359fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            byte[] data = getI18NameData(name);
1369fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            out.write((byte) data.length);
1379fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            out.write(data);
1389fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        }
1399fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        return out.toByteArray();
1409fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
1419fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1429fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
1439fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Format the raw bytes for the given {@link I18Name}.
1449fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     *
1459fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @param value The {@link I18Name} to serialize
1469fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @return byte[]
1479fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @throws IOException
1489fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
1499fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static byte[] getI18NameData(I18Name value) throws IOException {
1509fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        ByteArrayOutputStream out = new ByteArrayOutputStream();
1519fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(value.getLanguage().getBytes(StandardCharsets.US_ASCII));
1529fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write((byte) 0);    // Padding for language code.
1539fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(value.getText().getBytes(StandardCharsets.UTF_8));
1549fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        return out.toByteArray();
1559fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
1569fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1579fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
1589fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Write the lower 2-bytes of an integer to the given output stream in Little-Endian.
1599fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     *
1609fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @param out The output stream to write to
1619fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @param value The integer value to write
1629fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
1639fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static void writeShortLE(ByteArrayOutputStream out, int value) {
1649fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(value & 0xFF);
1659fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write((value >> 8) & 0xFF);
1669fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
1679fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu
1689fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    /**
1699fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * Write the given byte array to the given output stream, the array data is prefixed with a
1709fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * byte specifying the length of the byte array.
1719fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     *
1729fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @param out The output stream to write to
1739fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @param data The byte array to write
1749fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     * @throws IOException
1759fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu     */
1769fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    private static void writeByteArrayWithLength(ByteArrayOutputStream out, byte[] data)
1779fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu            throws IOException {
1789fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write((byte) data.length);
1799fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu        out.write(data);
1809fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu    }
1819fa8195087be42baed9f21ebdedadda9f509c7c6Peter Qiu}
182