/*
 * Copyright (C) 2017 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.lowpan;

import android.annotation.NonNull;
import android.icu.text.StringPrep;
import android.icu.text.StringPrepParseException;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.android.internal.util.HexDump;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;

Describes an instance of a LoWPAN network.
@hide
/** * Describes an instance of a LoWPAN network. * * @hide */
// @SystemApi public class LowpanIdentity implements Parcelable { private static final String TAG = LowpanIdentity.class.getSimpleName(); // Constants public static final int UNSPECIFIED_CHANNEL = -1; public static final int UNSPECIFIED_PANID = 0xFFFFFFFF; // Builder
@hide
/** @hide */
// @SystemApi public static class Builder { private static final StringPrep stringPrep = StringPrep.getInstance(StringPrep.RFC3920_RESOURCEPREP); final LowpanIdentity mIdentity = new LowpanIdentity(); private static String escape(@NonNull byte[] bytes) { StringBuffer sb = new StringBuffer(); for (byte b : bytes) { if (b >= 32 && b <= 126) { sb.append((char) b); } else { sb.append(String.format("\\0x%02x", b & 0xFF)); } } return sb.toString(); } public Builder setLowpanIdentity(@NonNull LowpanIdentity x) { Objects.requireNonNull(x); setRawName(x.getRawName()); setXpanid(x.getXpanid()); setPanid(x.getPanid()); setChannel(x.getChannel()); setType(x.getType()); return this; } public Builder setName(@NonNull String name) { Objects.requireNonNull(name); try { mIdentity.mName = stringPrep.prepare(name, StringPrep.DEFAULT); mIdentity.mRawName = mIdentity.mName.getBytes(StandardCharsets.UTF_8); mIdentity.mIsNameValid = true; } catch (StringPrepParseException x) { Log.w(TAG, x.toString()); setRawName(name.getBytes(StandardCharsets.UTF_8)); } return this; } public Builder setRawName(@NonNull byte[] name) { Objects.requireNonNull(name); mIdentity.mRawName = name.clone(); mIdentity.mName = new String(name, StandardCharsets.UTF_8); try { String nameCheck = stringPrep.prepare(mIdentity.mName, StringPrep.DEFAULT); mIdentity.mIsNameValid = Arrays.equals(nameCheck.getBytes(StandardCharsets.UTF_8), name); } catch (StringPrepParseException x) { Log.w(TAG, x.toString()); mIdentity.mIsNameValid = false; } // Non-normal names must be rendered differently to avoid confusion. if (!mIdentity.mIsNameValid) { mIdentity.mName = "«" + escape(name) + "»"; } return this; } public Builder setXpanid(byte x[]) { mIdentity.mXpanid = (x != null ? x.clone() : null); return this; } public Builder setPanid(int x) { mIdentity.mPanid = x; return this; } public Builder setType(@NonNull String x) { mIdentity.mType = x; return this; } public Builder setChannel(int x) { mIdentity.mChannel = x; return this; } public LowpanIdentity build() { return mIdentity; } } LowpanIdentity() {} // Instance Variables private String mName = ""; private boolean mIsNameValid = true; private byte[] mRawName = new byte[0]; private String mType = ""; private byte[] mXpanid = new byte[0]; private int mPanid = UNSPECIFIED_PANID; private int mChannel = UNSPECIFIED_CHANNEL; // Public Getters public String getName() { return mName; } public boolean isNameValid() { return mIsNameValid; } public byte[] getRawName() { return mRawName.clone(); } public byte[] getXpanid() { return mXpanid.clone(); } public int getPanid() { return mPanid; } public String getType() { return mType; } public int getChannel() { return mChannel; } @Override public String toString() { StringBuffer sb = new StringBuffer(); sb.append("Name:").append(getName()); if (mType.length() > 0) { sb.append(", Type:").append(mType); } if (mXpanid.length > 0) { sb.append(", XPANID:").append(HexDump.toHexString(mXpanid)); } if (mPanid != UNSPECIFIED_PANID) { sb.append(", PANID:").append(String.format("0x%04X", mPanid)); } if (mChannel != UNSPECIFIED_CHANNEL) { sb.append(", Channel:").append(mChannel); } return sb.toString(); } @Override public boolean equals(Object obj) { if (!(obj instanceof LowpanIdentity)) { return false; } LowpanIdentity rhs = (LowpanIdentity) obj; return Arrays.equals(mRawName, rhs.mRawName) && Arrays.equals(mXpanid, rhs.mXpanid) && mType.equals(rhs.mType) && mPanid == rhs.mPanid && mChannel == rhs.mChannel; } @Override public int hashCode() { return Objects.hash( Arrays.hashCode(mRawName), mType, Arrays.hashCode(mXpanid), mPanid, mChannel); }
Implement the Parcelable interface.
/** Implement the Parcelable interface. */
@Override public int describeContents() { return 0; }
Implement the Parcelable interface.
/** Implement the Parcelable interface. */
@Override public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(mRawName); dest.writeString(mType); dest.writeByteArray(mXpanid); dest.writeInt(mPanid); dest.writeInt(mChannel); }
Implement the Parcelable interface.
/** Implement the Parcelable interface. */
public static final Creator<LowpanIdentity> CREATOR = new Creator<LowpanIdentity>() { public LowpanIdentity createFromParcel(Parcel in) { Builder builder = new Builder(); builder.setRawName(in.createByteArray()); builder.setType(in.readString()); builder.setXpanid(in.createByteArray()); builder.setPanid(in.readInt()); builder.setChannel(in.readInt()); return builder.build(); } public LowpanIdentity[] newArray(int size) { return new LowpanIdentity[size]; } }; }