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 * @hide
28 */
29public final class PeriodicAdvertisingReport implements Parcelable {
30
31    /**
32     * The data returned is complete
33     */
34    public static final int DATA_COMPLETE = 0;
35
36    /**
37     * The data returned is incomplete. The controller was unsuccessfull to
38     * receive all chained packets, returning only partial data.
39     */
40    public static final int DATA_INCOMPLETE_TRUNCATED = 2;
41
42    private int syncHandle;
43    private int txPower;
44    private int rssi;
45    private int dataStatus;
46
47    // periodic advertising data.
48    @Nullable
49    private ScanRecord data;
50
51    // Device timestamp when the result was last seen.
52    private long timestampNanos;
53
54    /**
55     * Constructor of periodic advertising result.
56     *
57     */
58    public PeriodicAdvertisingReport(int syncHandle, int txPower, int rssi,
59                                     int dataStatus, ScanRecord data) {
60        this.syncHandle = syncHandle;
61        this.txPower = txPower;
62        this.rssi = rssi;
63        this.dataStatus = dataStatus;
64        this.data = 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(syncHandle);
74        dest.writeLong(txPower);
75        dest.writeInt(rssi);
76        dest.writeInt(dataStatus);
77        if (data != null) {
78            dest.writeInt(1);
79            dest.writeByteArray(data.getBytes());
80        } else {
81            dest.writeInt(0);
82        }
83    }
84
85    private void readFromParcel(Parcel in) {
86        syncHandle = in.readInt();
87        txPower = in.readInt();
88        rssi = in.readInt();
89        dataStatus = in.readInt();
90        if (in.readInt() == 1) {
91            data = 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 syncHandle;
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 txPower;
113    }
114
115    /**
116     * Returns the received signal strength in dBm. The valid range is [-127, 20].
117     */
118    public int getRssi() {
119        return rssi;
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 dataStatus;
128    }
129
130    /**
131     * Returns the data contained in this periodic advertising report.
132     */
133    @Nullable
134    public ScanRecord getData() {
135        return data;
136    }
137
138    /**
139     * Returns timestamp since boot when the scan record was observed.
140     */
141    public long getTimestampNanos() {
142        return timestampNanos;
143    }
144
145    @Override
146    public int hashCode() {
147        return Objects.hash(syncHandle, txPower, rssi, dataStatus, data, timestampNanos);
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 (syncHandle == other.syncHandle) &&
160            (txPower == other.txPower) &&
161            (rssi == other.rssi) &&
162            (dataStatus == other.dataStatus) &&
163            Objects.equals(data, other.data) &&
164            (timestampNanos == other.timestampNanos);
165    }
166
167    @Override
168    public String toString() {
169      return "PeriodicAdvertisingReport{syncHandle=" + syncHandle +
170          ", txPower=" + txPower + ", rssi=" + rssi + ", dataStatus=" + dataStatus +
171          ", data=" + Objects.toString(data) + ", timestampNanos=" + timestampNanos + '}';
172    }
173
174    public static final Parcelable.Creator<PeriodicAdvertisingReport> CREATOR = new Creator<PeriodicAdvertisingReport>() {
175            @Override
176        public PeriodicAdvertisingReport createFromParcel(Parcel source) {
177            return new PeriodicAdvertisingReport(source);
178        }
179
180            @Override
181        public PeriodicAdvertisingReport[] newArray(int size) {
182            return new PeriodicAdvertisingReport[size];
183        }
184    };
185}
186