1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.net.lowpan;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import com.android.internal.util.HexDump;
22import java.util.Arrays;
23import java.util.Collection;
24import java.util.Objects;
25import java.util.TreeSet;
26
27/**
28 * Describes a LoWPAN Beacon
29 *
30 * @hide
31 */
32// @SystemApi
33public class LowpanBeaconInfo implements Parcelable {
34    public static final int UNKNOWN_RSSI = Integer.MAX_VALUE;
35    public static final int UNKNOWN_LQI = 0;
36
37    private LowpanIdentity mIdentity;
38    private int mRssi = UNKNOWN_RSSI;
39    private int mLqi = UNKNOWN_LQI;
40    private byte[] mBeaconAddress = null;
41    private final TreeSet<Integer> mFlags = new TreeSet<>();
42
43    public static final int FLAG_CAN_ASSIST = 1;
44
45    /** @hide */
46    public static class Builder {
47        final LowpanIdentity.Builder mIdentityBuilder = new LowpanIdentity.Builder();
48        final LowpanBeaconInfo mBeaconInfo = new LowpanBeaconInfo();
49
50        public Builder setLowpanIdentity(LowpanIdentity x) {
51            mIdentityBuilder.setLowpanIdentity(x);
52            return this;
53        }
54
55        public Builder setName(String x) {
56            mIdentityBuilder.setName(x);
57            return this;
58        }
59
60        public Builder setXpanid(byte x[]) {
61            mIdentityBuilder.setXpanid(x);
62            return this;
63        }
64
65        public Builder setPanid(int x) {
66            mIdentityBuilder.setPanid(x);
67            return this;
68        }
69
70        public Builder setChannel(int x) {
71            mIdentityBuilder.setChannel(x);
72            return this;
73        }
74
75        public Builder setType(String x) {
76            mIdentityBuilder.setType(x);
77            return this;
78        }
79
80        public Builder setRssi(int x) {
81            mBeaconInfo.mRssi = x;
82            return this;
83        }
84
85        public Builder setLqi(int x) {
86            mBeaconInfo.mLqi = x;
87            return this;
88        }
89
90        public Builder setBeaconAddress(byte x[]) {
91            mBeaconInfo.mBeaconAddress = (x != null ? x.clone() : null);
92            return this;
93        }
94
95        public Builder setFlag(int x) {
96            mBeaconInfo.mFlags.add(x);
97            return this;
98        }
99
100        public Builder setFlags(Collection<Integer> x) {
101            mBeaconInfo.mFlags.addAll(x);
102            return this;
103        }
104
105        public LowpanBeaconInfo build() {
106            mBeaconInfo.mIdentity = mIdentityBuilder.build();
107            if (mBeaconInfo.mBeaconAddress == null) {
108                mBeaconInfo.mBeaconAddress = new byte[0];
109            }
110            return mBeaconInfo;
111        }
112    }
113
114    private LowpanBeaconInfo() {}
115
116    public LowpanIdentity getLowpanIdentity() {
117        return mIdentity;
118    }
119
120    public int getRssi() {
121        return mRssi;
122    }
123
124    public int getLqi() {
125        return mLqi;
126    }
127
128    public byte[] getBeaconAddress() {
129        return mBeaconAddress.clone();
130    }
131
132    public Collection<Integer> getFlags() {
133        return (Collection<Integer>) mFlags.clone();
134    }
135
136    public boolean isFlagSet(int flag) {
137        return mFlags.contains(flag);
138    }
139
140    @Override
141    public String toString() {
142        StringBuffer sb = new StringBuffer();
143
144        sb.append(mIdentity.toString());
145
146        if (mRssi != UNKNOWN_RSSI) {
147            sb.append(", RSSI:").append(mRssi).append("dBm");
148        }
149
150        if (mLqi != UNKNOWN_LQI) {
151            sb.append(", LQI:").append(mLqi);
152        }
153
154        if (mBeaconAddress.length > 0) {
155            sb.append(", BeaconAddress:").append(HexDump.toHexString(mBeaconAddress));
156        }
157
158        for (Integer flag : mFlags) {
159            switch (flag.intValue()) {
160                case FLAG_CAN_ASSIST:
161                    sb.append(", CAN_ASSIST");
162                    break;
163                default:
164                    sb.append(", FLAG_").append(Integer.toHexString(flag));
165                    break;
166            }
167        }
168
169        return sb.toString();
170    }
171
172    @Override
173    public int hashCode() {
174        return Objects.hash(mIdentity, mRssi, mLqi, Arrays.hashCode(mBeaconAddress), mFlags);
175    }
176
177    @Override
178    public boolean equals(Object obj) {
179        if (!(obj instanceof LowpanBeaconInfo)) {
180            return false;
181        }
182        LowpanBeaconInfo rhs = (LowpanBeaconInfo) obj;
183        return mIdentity.equals(rhs.mIdentity)
184                && Arrays.equals(mBeaconAddress, rhs.mBeaconAddress)
185                && mRssi == rhs.mRssi
186                && mLqi == rhs.mLqi
187                && mFlags.equals(rhs.mFlags);
188    }
189
190    /** Implement the Parcelable interface. */
191    @Override
192    public int describeContents() {
193        return 0;
194    }
195
196    /** Implement the Parcelable interface. */
197    @Override
198    public void writeToParcel(Parcel dest, int flags) {
199        mIdentity.writeToParcel(dest, flags);
200        dest.writeInt(mRssi);
201        dest.writeInt(mLqi);
202        dest.writeByteArray(mBeaconAddress);
203
204        dest.writeInt(mFlags.size());
205        for (Integer val : mFlags) {
206            dest.writeInt(val);
207        }
208    }
209
210    /** Implement the Parcelable interface. */
211    public static final Creator<LowpanBeaconInfo> CREATOR =
212            new Creator<LowpanBeaconInfo>() {
213                public LowpanBeaconInfo createFromParcel(Parcel in) {
214                    Builder builder = new Builder();
215
216                    builder.setLowpanIdentity(LowpanIdentity.CREATOR.createFromParcel(in));
217
218                    builder.setRssi(in.readInt());
219                    builder.setLqi(in.readInt());
220
221                    builder.setBeaconAddress(in.createByteArray());
222
223                    for (int i = in.readInt(); i > 0; i--) {
224                        builder.setFlag(in.readInt());
225                    }
226
227                    return builder.build();
228                }
229
230                public LowpanBeaconInfo[] newArray(int size) {
231                    return new LowpanBeaconInfo[size];
232                }
233            };
234}
235