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.bluetooth.le;
18
19import android.annotation.Nullable;
20import android.os.Parcel;
21import android.os.Parcelable;
22
23import java.util.Objects;
24
25/**
26 * PeriodicAdvertisingReport for Bluetooth LE synchronized advertising.
27 *
28 * @hide
29 */
30public final class PeriodicAdvertisingReport implements Parcelable {
31
32    /**
33     * The data returned is complete
34     */
35    public static final int DATA_COMPLETE = 0;
36
37    /**
38     * The data returned is incomplete. The controller was unsuccessfull to
39     * receive all chained packets, returning only partial data.
40     */
41    public static final int DATA_INCOMPLETE_TRUNCATED = 2;
42
43    private int mSyncHandle;
44    private int mTxPower;
45    private int mRssi;
46    private int mDataStatus;
47
48    // periodic advertising data.
49    @Nullable
50    private ScanRecord mData;
51
52    // Device timestamp when the result was last seen.
53    private long mTimestampNanos;
54
55    /**
56     * Constructor of periodic advertising result.
57     */
58    public PeriodicAdvertisingReport(int syncHandle, int txPower, int rssi,
59            int dataStatus, ScanRecord data) {
60        mSyncHandle = syncHandle;
61        mTxPower = txPower;
62        mRssi = rssi;
63        mDataStatus = dataStatus;
64        mData = data;
65    }
66
67    private PeriodicAdvertisingReport(Parcel in) {
68        readFromParcel(in);
69    }
70
71    @Override
72    public void writeToParcel(Parcel dest, int flags) {
73        dest.writeInt(mSyncHandle);
74        dest.writeInt(mTxPower);
75        dest.writeInt(mRssi);
76        dest.writeInt(mDataStatus);
77        if (mData != null) {
78            dest.writeInt(1);
79            dest.writeByteArray(mData.getBytes());
80        } else {
81            dest.writeInt(0);
82        }
83    }
84
85    private void readFromParcel(Parcel in) {
86        mSyncHandle = in.readInt();
87        mTxPower = in.readInt();
88        mRssi = in.readInt();
89        mDataStatus = in.readInt();
90        if (in.readInt() == 1) {
91            mData = ScanRecord.parseFromBytes(in.createByteArray());
92        }
93    }
94
95    @Override
96    public int describeContents() {
97        return 0;
98    }
99
100    /**
101     * Returns the synchronization handle.
102     */
103    public int getSyncHandle() {
104        return mSyncHandle;
105    }
106
107    /**
108     * Returns the transmit power in dBm. The valid range is [-127, 126]. Value
109     * of 127 means information was not available.
110     */
111    public int getTxPower() {
112        return mTxPower;
113    }
114
115    /**
116     * Returns the received signal strength in dBm. The valid range is [-127, 20].
117     */
118    public int getRssi() {
119        return mRssi;
120    }
121
122    /**
123     * Returns the data status. Can be one of {@link PeriodicAdvertisingReport#DATA_COMPLETE}
124     * or {@link PeriodicAdvertisingReport#DATA_INCOMPLETE_TRUNCATED}.
125     */
126    public int getDataStatus() {
127        return mDataStatus;
128    }
129
130    /**
131     * Returns the data contained in this periodic advertising report.
132     */
133    @Nullable
134    public ScanRecord getData() {
135        return mData;
136    }
137
138    /**
139     * Returns timestamp since boot when the scan record was observed.
140     */
141    public long getTimestampNanos() {
142        return mTimestampNanos;
143    }
144
145    @Override
146    public int hashCode() {
147        return Objects.hash(mSyncHandle, mTxPower, mRssi, mDataStatus, mData, mTimestampNanos);
148    }
149
150    @Override
151    public boolean equals(Object obj) {
152        if (this == obj) {
153            return true;
154        }
155        if (obj == null || getClass() != obj.getClass()) {
156            return false;
157        }
158        PeriodicAdvertisingReport other = (PeriodicAdvertisingReport) obj;
159        return (mSyncHandle == other.mSyncHandle)
160                && (mTxPower == other.mTxPower)
161                && (mRssi == other.mRssi)
162                && (mDataStatus == other.mDataStatus)
163                && Objects.equals(mData, other.mData)
164                && (mTimestampNanos == other.mTimestampNanos);
165    }
166
167    @Override
168    public String toString() {
169        return "PeriodicAdvertisingReport{syncHandle=" + mSyncHandle
170                + ", txPower=" + mTxPower + ", rssi=" + mRssi + ", dataStatus=" + mDataStatus
171                + ", data=" + Objects.toString(mData) + ", timestampNanos=" + mTimestampNanos + '}';
172    }
173
174    public static final Parcelable.Creator<PeriodicAdvertisingReport> CREATOR =
175            new Creator<PeriodicAdvertisingReport>() {
176                @Override
177                public PeriodicAdvertisingReport createFromParcel(Parcel source) {
178                    return new PeriodicAdvertisingReport(source);
179                }
180
181                @Override
182                public PeriodicAdvertisingReport[] newArray(int size) {
183                    return new PeriodicAdvertisingReport[size];
184                }
185            };
186}
187