1 /*
2  * Copyright (C) 2022 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.app.ambientcontext;
18 
19 import android.annotation.NonNull;
20 import android.annotation.SystemApi;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.os.PersistableBundle;
24 import android.util.ArraySet;
25 
26 import com.android.internal.util.AnnotationValidations;
27 import com.android.internal.util.Preconditions;
28 
29 import java.util.HashSet;
30 import java.util.Set;
31 
32 /**
33  * Represents the request for ambient event detection.
34  *
35  * @hide
36  */
37 @SystemApi
38 public final class AmbientContextEventRequest implements Parcelable {
39     @NonNull private final Set<Integer> mEventTypes;
40     @NonNull private final PersistableBundle mOptions;
41 
AmbientContextEventRequest( @onNull Set<Integer> eventTypes, @NonNull PersistableBundle options)42     private AmbientContextEventRequest(
43             @NonNull Set<Integer> eventTypes,
44             @NonNull PersistableBundle options) {
45         this.mEventTypes = eventTypes;
46         AnnotationValidations.validate(NonNull.class, null, mEventTypes);
47         Preconditions.checkArgument(!eventTypes.isEmpty(), "eventTypes cannot be empty");
48         for (int eventType : eventTypes) {
49             AnnotationValidations.validate(AmbientContextEvent.EventCode.class, null, eventType);
50         }
51         this.mOptions = options;
52         AnnotationValidations.validate(NonNull.class, null, mOptions);
53     }
54 
55     /**
56      * The event types to detect.
57      */
getEventTypes()58     public @NonNull Set<Integer> getEventTypes() {
59         return mEventTypes;
60     }
61 
62     /**
63      * Optional detection options.
64      */
getOptions()65     public @NonNull PersistableBundle getOptions() {
66         return mOptions;
67     }
68 
69     @Override
toString()70     public String toString() {
71         return "AmbientContextEventRequest { " + "eventTypes = " + mEventTypes + ", "
72                 + "options = " + mOptions + " }";
73     }
74 
75     @Override
writeToParcel(@onNull Parcel dest, int flags)76     public void writeToParcel(@NonNull Parcel dest, int flags) {
77         dest.writeArraySet(new ArraySet<>(mEventTypes));
78         dest.writeTypedObject(mOptions, flags);
79     }
80 
81     @Override
describeContents()82     public int describeContents() {
83         return 0;
84     }
85 
86     /** @hide */
87     @SuppressWarnings({"unchecked", "RedundantCast"})
AmbientContextEventRequest(@onNull Parcel in)88     private AmbientContextEventRequest(@NonNull Parcel in) {
89         Set<Integer> eventTypes = (Set<Integer>) in.readArraySet(Integer.class.getClassLoader());
90         PersistableBundle options = (PersistableBundle) in.readTypedObject(
91                 PersistableBundle.CREATOR);
92 
93         this.mEventTypes = eventTypes;
94         AnnotationValidations.validate(
95                 NonNull.class, null, mEventTypes);
96         Preconditions.checkArgument(!eventTypes.isEmpty(), "eventTypes cannot be empty");
97         for (int eventType : eventTypes) {
98             AnnotationValidations.validate(AmbientContextEvent.EventCode.class, null, eventType);
99         }
100         this.mOptions = options;
101         AnnotationValidations.validate(
102                 NonNull.class, null, mOptions);
103     }
104 
105     public static final @NonNull Parcelable.Creator<AmbientContextEventRequest> CREATOR =
106             new Parcelable.Creator<AmbientContextEventRequest>() {
107         @Override
108         public AmbientContextEventRequest[] newArray(int size) {
109             return new AmbientContextEventRequest[size];
110         }
111 
112         @Override
113         public AmbientContextEventRequest createFromParcel(@NonNull Parcel in) {
114             return new AmbientContextEventRequest(in);
115         }
116     };
117 
118     /**
119      * A builder for {@link AmbientContextEventRequest}
120      */
121     @SuppressWarnings("WeakerAccess")
122     public static final class Builder {
123         private @NonNull Set<Integer> mEventTypes;
124         private @NonNull PersistableBundle mOptions;
125 
126         private long mBuilderFieldsSet = 0L;
127 
Builder()128         public Builder() {
129         }
130 
131         /**
132          * Add an event type to detect.
133          */
addEventType(@mbientContextEvent.EventCode int value)134         public @NonNull Builder addEventType(@AmbientContextEvent.EventCode int value) {
135             checkNotUsed();
136             if (mEventTypes == null) {
137                 mBuilderFieldsSet |= 0x1;
138                 mEventTypes = new HashSet<>();
139             }
140             mEventTypes.add(value);
141             return this;
142         }
143 
144         /**
145          * Optional detection options.
146          */
setOptions(@onNull PersistableBundle value)147         public @NonNull Builder setOptions(@NonNull PersistableBundle value) {
148             checkNotUsed();
149             mBuilderFieldsSet |= 0x2;
150             mOptions = value;
151             return this;
152         }
153 
154         /** Builds the instance. This builder should not be touched after calling this! */
build()155         public @NonNull AmbientContextEventRequest build() {
156             checkNotUsed();
157             mBuilderFieldsSet |= 0x4; // Mark builder used
158 
159             if ((mBuilderFieldsSet & 0x1) == 0) {
160                 mEventTypes = new HashSet<>();
161             }
162             if ((mBuilderFieldsSet & 0x2) == 0) {
163                 mOptions = new PersistableBundle();
164             }
165             AmbientContextEventRequest o = new AmbientContextEventRequest(
166                     mEventTypes,
167                     mOptions);
168             return o;
169         }
170 
checkNotUsed()171         private void checkNotUsed() {
172             if ((mBuilderFieldsSet & 0x4) != 0) {
173                 throw new IllegalStateException(
174                         "This Builder should not be reused. Use a new Builder instance instead");
175             }
176         }
177     }
178 }
179