1 /*
2  * Copyright (C) 2024 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 
17 package android.companion;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.os.Parcel;
24 import android.os.ParcelUuid;
25 import android.os.Parcelable;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.util.Objects;
30 
31 /**
32  * Event for observing device presence.
33  *
34  * @see CompanionDeviceManager#startObservingDevicePresence(ObservingDevicePresenceRequest)
35  * @see ObservingDevicePresenceRequest.Builder#setUuid(ParcelUuid)
36  * @see ObservingDevicePresenceRequest.Builder#setAssociationId(int)
37  */
38 @FlaggedApi(Flags.FLAG_DEVICE_PRESENCE)
39 public final class DevicePresenceEvent implements Parcelable {
40 
41     /** @hide */
42     @IntDef(prefix = {"EVENT"}, value = {
43             EVENT_BLE_APPEARED,
44             EVENT_BLE_DISAPPEARED,
45             EVENT_BT_CONNECTED,
46             EVENT_BT_DISCONNECTED,
47             EVENT_SELF_MANAGED_APPEARED,
48             EVENT_SELF_MANAGED_DISAPPEARED
49     })
50 
51     @Retention(RetentionPolicy.SOURCE)
52     public @interface Event {}
53 
54     /**
55      * Indicate observing device presence base on the ParcelUuid but not association id.
56      */
57     public static final int NO_ASSOCIATION = -1;
58 
59     /**
60      * Companion app receives
61      * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} callback
62      * with this event if the device comes into BLE range.
63      */
64     public static final int EVENT_BLE_APPEARED = 0;
65 
66     /**
67      * Companion app receives
68      * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} callback
69      * with this event if the device is no longer in BLE range.
70      */
71     public static final int EVENT_BLE_DISAPPEARED = 1;
72 
73     /**
74      * Companion app receives
75      * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} callback
76      * with this event when the bluetooth device is connected.
77      */
78     public static final int EVENT_BT_CONNECTED = 2;
79 
80     /**
81      * Companion app receives
82      * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} callback
83      * with this event if the bluetooth device is disconnected.
84      */
85     public static final int EVENT_BT_DISCONNECTED = 3;
86 
87     /**
88      * A companion app for a self-managed device will receive the callback
89      * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)}
90      * if it reports that a device has appeared on its
91      * own.
92      */
93     public static final int EVENT_SELF_MANAGED_APPEARED = 4;
94 
95     /**
96      * A companion app for a self-managed device will receive the callback
97      * {@link CompanionDeviceService#onDevicePresenceEvent(DevicePresenceEvent)} if it reports
98      * that a device has disappeared on its own.
99      */
100     public static final int EVENT_SELF_MANAGED_DISAPPEARED = 5;
101     private final int mAssociationId;
102     private final int mEvent;
103     @Nullable
104     private final ParcelUuid mUuid;
105 
106     private static final int PARCEL_UUID_NULL = 0;
107 
108     private static final int PARCEL_UUID_NOT_NULL = 1;
109 
110     /**
111      * Create a new DevicePresenceEvent.
112      */
DevicePresenceEvent( int associationId, @Event int event, @Nullable ParcelUuid uuid)113     public DevicePresenceEvent(
114             int associationId, @Event int event, @Nullable ParcelUuid uuid) {
115         mAssociationId = associationId;
116         mEvent = event;
117         mUuid = uuid;
118     }
119 
120     /**
121      * @return The association id has been used to observe device presence.
122      *
123      * Caller will receive the valid association id if only if using
124      * {@link ObservingDevicePresenceRequest.Builder#setAssociationId(int)}, otherwise
125      * return {@link #NO_ASSOCIATION}.
126      *
127      * @see ObservingDevicePresenceRequest.Builder#setAssociationId(int)
128      */
getAssociationId()129     public int getAssociationId() {
130         return mAssociationId;
131     }
132 
133     /**
134      * @return Associated companion device's event.
135      */
getEvent()136     public int getEvent() {
137         return mEvent;
138     }
139 
140     /**
141      * @return The ParcelUuid has been used to observe device presence.
142      *
143      * Caller will receive the ParcelUuid if only if using
144      * {@link ObservingDevicePresenceRequest.Builder#setUuid(ParcelUuid)}, otherwise return null.
145      *
146      * @see ObservingDevicePresenceRequest.Builder#setUuid(ParcelUuid)
147      */
148 
149     @Nullable
getUuid()150     public ParcelUuid getUuid() {
151         return mUuid;
152     }
153 
154     @Override
describeContents()155     public int describeContents() {
156         return 0;
157     }
158 
159     @Override
writeToParcel(@onNull Parcel dest, int flags)160     public void writeToParcel(@NonNull Parcel dest, int flags) {
161         dest.writeInt(mAssociationId);
162         dest.writeInt(mEvent);
163         if (mUuid == null) {
164             // Write 0 to the parcel to indicate the ParcelUuid is null.
165             dest.writeInt(PARCEL_UUID_NULL);
166         } else {
167             dest.writeInt(PARCEL_UUID_NOT_NULL);
168             mUuid.writeToParcel(dest, flags);
169         }
170     }
171 
172     @Override
equals(@ullable Object o)173     public boolean equals(@Nullable Object o) {
174         if (this == o) return true;
175         if (!(o instanceof DevicePresenceEvent that)) return false;
176 
177         return Objects.equals(mUuid, that.mUuid)
178                 && mAssociationId == that.mAssociationId
179                 && mEvent == that.mEvent;
180     }
181 
182     @Override
toString()183     public String toString() {
184         return "ObservingDevicePresenceResult { "
185                 + "Association Id= " + mAssociationId + ","
186                 + "ParcelUuid= " + mUuid + ","
187                 + "Event= " + mEvent + "}";
188     }
189 
190     @Override
hashCode()191     public int hashCode() {
192         return Objects.hash(mAssociationId, mEvent, mUuid);
193     }
194 
195     @NonNull
196     public static final Parcelable.Creator<DevicePresenceEvent> CREATOR =
197             new Parcelable.Creator<DevicePresenceEvent>() {
198                 @Override
199                 public DevicePresenceEvent[] newArray(int size) {
200                     return new DevicePresenceEvent[size];
201                 }
202 
203                 @Override
204                 public DevicePresenceEvent createFromParcel(@NonNull Parcel in) {
205                     return new DevicePresenceEvent(in);
206                 }
207             };
208 
DevicePresenceEvent(@onNull Parcel in)209     private DevicePresenceEvent(@NonNull Parcel in) {
210         mAssociationId = in.readInt();
211         mEvent = in.readInt();
212         if (in.readInt() == PARCEL_UUID_NULL) {
213             mUuid = null;
214         } else {
215             mUuid = ParcelUuid.CREATOR.createFromParcel(in);
216         }
217     }
218 }
219