237 lines
7.8 KiB
Java
237 lines
7.8 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2012 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.net.wifi;
|
||
|
|
||
|
import android.annotation.NonNull;
|
||
|
import android.annotation.Nullable;
|
||
|
import android.compat.annotation.UnsupportedAppUsage;
|
||
|
import android.net.wifi.util.HexEncoding;
|
||
|
import android.os.Parcel;
|
||
|
import android.os.Parcelable;
|
||
|
import android.text.TextUtils;
|
||
|
|
||
|
import java.io.ByteArrayOutputStream;
|
||
|
import java.nio.ByteBuffer;
|
||
|
import java.nio.CharBuffer;
|
||
|
import java.nio.charset.Charset;
|
||
|
import java.nio.charset.CharsetDecoder;
|
||
|
import java.nio.charset.CoderResult;
|
||
|
import java.nio.charset.CodingErrorAction;
|
||
|
import java.nio.charset.StandardCharsets;
|
||
|
import java.util.Arrays;
|
||
|
|
||
|
/**
|
||
|
* Representation of a Wi-Fi Service Set Identifier (SSID).
|
||
|
*/
|
||
|
public final class WifiSsid implements Parcelable {
|
||
|
private final byte[] mBytes;
|
||
|
|
||
|
/**
|
||
|
* Creates a WifiSsid from the raw bytes. If the byte array is null, creates an empty WifiSsid
|
||
|
* object which will return an empty byte array and empty text.
|
||
|
* @param bytes the SSID
|
||
|
*/
|
||
|
private WifiSsid(@Nullable byte[] bytes) {
|
||
|
if (bytes == null) {
|
||
|
bytes = new byte[0];
|
||
|
}
|
||
|
mBytes = bytes;
|
||
|
// Duplicate the bytes to #octets for legacy apps.
|
||
|
octets.write(bytes, 0, bytes.length);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a WifiSsid from the raw bytes. If the byte array is null, return an empty WifiSsid
|
||
|
* object which will return an empty byte array and empty text.
|
||
|
*/
|
||
|
@NonNull
|
||
|
public static WifiSsid fromBytes(@Nullable byte[] bytes) {
|
||
|
return new WifiSsid(bytes);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the raw byte array representing this SSID.
|
||
|
* @return the SSID
|
||
|
*/
|
||
|
@NonNull
|
||
|
public byte[] getBytes() {
|
||
|
return mBytes.clone();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a UTF-8 WifiSsid from unquoted plaintext. If the text is null, return an
|
||
|
* empty WifiSsid object which will return an empty byte array and empty text.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public static WifiSsid fromUtf8Text(@Nullable CharSequence utf8Text) {
|
||
|
if (utf8Text == null) {
|
||
|
return new WifiSsid(null);
|
||
|
}
|
||
|
return new WifiSsid(utf8Text.toString().getBytes(StandardCharsets.UTF_8));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If the SSID is encoded with UTF-8, this method returns the decoded SSID as plaintext.
|
||
|
* Otherwise, it returns {@code null}.
|
||
|
* @return the SSID
|
||
|
* @hide
|
||
|
*/
|
||
|
@Nullable
|
||
|
public CharSequence getUtf8Text() {
|
||
|
return decodeSsid(mBytes, StandardCharsets.UTF_8);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Create a WifiSsid from a string matching the format of {@link WifiSsid#toString()}.
|
||
|
* If the string is null, return an empty WifiSsid object which will return an empty byte array
|
||
|
* and empty text.
|
||
|
* @throws IllegalArgumentException if the string is unquoted but not hexadecimal,
|
||
|
* or if the hexadecimal string is odd-length.
|
||
|
* @hide
|
||
|
*/
|
||
|
@NonNull
|
||
|
public static WifiSsid fromString(@Nullable String string) {
|
||
|
if (string == null) {
|
||
|
return new WifiSsid(null);
|
||
|
}
|
||
|
final int length = string.length();
|
||
|
if ((length > 1) && (string.charAt(0) == '"') && (string.charAt(length - 1) == '"')) {
|
||
|
return new WifiSsid(string.substring(1, length - 1).getBytes(StandardCharsets.UTF_8));
|
||
|
}
|
||
|
return new WifiSsid(HexEncoding.decode(string));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the string representation of the WifiSsid. If the SSID can be decoded as UTF-8, it
|
||
|
* will be returned in plain text surrounded by double quotation marks. Otherwise, it is
|
||
|
* returned as an unquoted string of hex digits. This format is consistent with
|
||
|
* {@link WifiInfo#getSSID()} and {@link WifiConfiguration#SSID}.
|
||
|
*
|
||
|
* @return SSID as double-quoted plain text from UTF-8 or unquoted hex digits
|
||
|
*/
|
||
|
@Override
|
||
|
@NonNull
|
||
|
public String toString() {
|
||
|
String utf8String = decodeSsid(mBytes, StandardCharsets.UTF_8);
|
||
|
if (TextUtils.isEmpty(utf8String)) {
|
||
|
return HexEncoding.encodeToString(mBytes, false /* upperCase */);
|
||
|
}
|
||
|
return "\"" + utf8String + "\"";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the given SSID bytes as a String decoded using the given Charset. If the bytes cannot
|
||
|
* be decoded, then this returns {@code null}.
|
||
|
* @param ssidBytes SSID as bytes
|
||
|
* @param charset Charset to decode with
|
||
|
* @return SSID as string, or {@code null}.
|
||
|
*/
|
||
|
@Nullable
|
||
|
private static String decodeSsid(@NonNull byte[] ssidBytes, @NonNull Charset charset) {
|
||
|
CharsetDecoder decoder = charset.newDecoder()
|
||
|
.onMalformedInput(CodingErrorAction.REPORT)
|
||
|
.onUnmappableCharacter(CodingErrorAction.REPORT);
|
||
|
CharBuffer out = CharBuffer.allocate(32);
|
||
|
CoderResult result = decoder.decode(ByteBuffer.wrap(ssidBytes), out, true);
|
||
|
out.flip();
|
||
|
if (result.isError()) {
|
||
|
return null;
|
||
|
}
|
||
|
return out.toString();
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public boolean equals(Object thatObject) {
|
||
|
if (this == thatObject) {
|
||
|
return true;
|
||
|
}
|
||
|
if (!(thatObject instanceof WifiSsid)) {
|
||
|
return false;
|
||
|
}
|
||
|
WifiSsid that = (WifiSsid) thatObject;
|
||
|
return Arrays.equals(mBytes, that.mBytes);
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public int hashCode() {
|
||
|
return Arrays.hashCode(mBytes);
|
||
|
}
|
||
|
|
||
|
/** Implement the Parcelable interface */
|
||
|
@Override
|
||
|
public int describeContents() {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/** Implement the Parcelable interface */
|
||
|
@Override
|
||
|
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||
|
dest.writeByteArray(mBytes);
|
||
|
}
|
||
|
|
||
|
/** Implement the Parcelable interface */
|
||
|
public static final @NonNull Creator<WifiSsid> CREATOR =
|
||
|
new Creator<WifiSsid>() {
|
||
|
@Override
|
||
|
public WifiSsid createFromParcel(Parcel in) {
|
||
|
return new WifiSsid(in.createByteArray());
|
||
|
}
|
||
|
|
||
|
@Override
|
||
|
public WifiSsid[] newArray(int size) {
|
||
|
return new WifiSsid[size];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Use {@link #getBytes()} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
// TODO(b/231433398): add maxTargetSdk = Build.VERSION_CODES.S
|
||
|
@UnsupportedAppUsage(publicAlternatives = "{@link #getBytes()}")
|
||
|
public final ByteArrayOutputStream octets = new ByteArrayOutputStream(32);
|
||
|
|
||
|
/**
|
||
|
* Use {@link android.net.wifi.WifiManager#UNKNOWN_SSID} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
// TODO(b/231433398): add maxTargetSdk = Build.VERSION_CODES.S
|
||
|
@UnsupportedAppUsage(publicAlternatives = "{@link android.net.wifi.WifiManager#UNKNOWN_SSID}")
|
||
|
public static final String NONE = WifiManager.UNKNOWN_SSID;
|
||
|
|
||
|
/**
|
||
|
* Use {@link #fromBytes(byte[])} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
// TODO(b/231433398): add maxTargetSdk = Build.VERSION_CODES.S
|
||
|
@UnsupportedAppUsage(publicAlternatives = "{@link #fromBytes(byte[])}")
|
||
|
public static WifiSsid createFromAsciiEncoded(String asciiEncoded) {
|
||
|
return fromUtf8Text(asciiEncoded);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Use {@link #getBytes()} instead.
|
||
|
* @hide
|
||
|
*/
|
||
|
// TODO(b/231433398): add maxTargetSdk = Build.VERSION_CODES.S
|
||
|
@UnsupportedAppUsage(publicAlternatives = "{@link #getBytes()}")
|
||
|
public byte[] getOctets() {
|
||
|
return getBytes();
|
||
|
}
|
||
|
}
|