• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.car.drivingstate;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.IntDef;
22 import android.car.annotation.AddedInOrBefore;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 
31 /**
32  * Car UX Restrictions event.  This contains information on the set of UX restrictions that is in
33  * place due to the car's driving state.
34  * <p>
35  * The restriction information is organized as follows:
36  * <ul>
37  * <li> When there are no restrictions in place, for example when the car is parked,
38  * <ul>
39  * <li> {@link #isRequiresDistractionOptimization()} returns false.  Apps can display activities
40  * that are not distraction optimized.
41  * <li> When {@link #isRequiresDistractionOptimization()} returns false, apps don't have to call
42  * {@link #getActiveRestrictions()}, since there is no distraction optimization required.
43  * </ul>
44  * <li> When the driving state changes, causing the UX restrictions to come in effect,
45  * <ul>
46  * <li> {@link #isRequiresDistractionOptimization()} returns true.  Apps can only display activities
47  * that are distraction optimized.  Distraction optimized activities must follow the base design
48  * guidelines to ensure a distraction free driving experience for the user.
49  * <li> When {@link #isRequiresDistractionOptimization()} returns true, apps must call
50  * {@link #getActiveRestrictions()}, to get the currently active UX restrictions to adhere to.
51  * {@link #getActiveRestrictions()} provides additional information on the set of UX
52  * restrictions that are in place for the current driving state.
53  * <p>
54  * The UX restrictions returned by {@link #getActiveRestrictions()}, for the same driving state of
55  * the vehicle, could vary depending on the OEM and the market.  For example, when the car is
56  * idling, the set of active UX restrictions will depend on the car maker and the safety standards
57  * of the market that the vehicle is deployed in.
58  * </ul>
59  * </ul>
60  * <p>
61  * Apps that intend to be run when the car is being driven need to
62  * <ul>
63  * <li> Comply with the general distraction optimization guidelines.
64  * <li> Listen and react to the UX restrictions changes as detailed above.  Since the restrictions
65  * could vary depending on the market, apps are expected to react to the restriction information
66  * and not to the absolute driving state.
67  * </ul>
68  */
69 public final class CarUxRestrictions implements Parcelable {
70 
71     // Default fallback values for the restriction related parameters if the information is
72     // not available from the underlying service.
73     private static final int DEFAULT_MAX_LENGTH = 120;
74     private static final int DEFAULT_MAX_CUMULATIVE_ITEMS = 21;
75     private static final int DEFAULT_MAX_CONTENT_DEPTH = 3;
76 
77     /**
78      * No specific restrictions in place, but baseline distraction optimization guidelines need to
79      * be adhered to when {@link #isRequiresDistractionOptimization()} is true.
80      */
81     @AddedInOrBefore(majorVersion = 33)
82     public static final int UX_RESTRICTIONS_BASELINE = 0;
83 
84     // Granular UX Restrictions that are imposed when distraction optimization is required.
85     /**
86      * No dialpad for the purpose of initiating a phone call.
87      */
88     @AddedInOrBefore(majorVersion = 33)
89     public static final int UX_RESTRICTIONS_NO_DIALPAD = 1;
90 
91     /**
92      * No filtering a list with alpha-numeric character via the use of a character entry method.
93      *
94      * For example, do not allow entering a letter to filter the content of a list down to
95      * items only containing that letter.
96      */
97     @AddedInOrBefore(majorVersion = 33)
98     public static final int UX_RESTRICTIONS_NO_FILTERING = 0x1 << 1;
99 
100     /**
101      * General purpose strings length cannot exceed the character limit provided by
102      * {@link #getMaxRestrictedStringLength()}
103      */
104     @AddedInOrBefore(majorVersion = 33)
105     public static final int UX_RESTRICTIONS_LIMIT_STRING_LENGTH = 0x1 << 2;
106 
107     /**
108      * No text entry for the purpose of searching or other manual text string entry actvities.
109      */
110     @AddedInOrBefore(majorVersion = 33)
111     public static final int UX_RESTRICTIONS_NO_KEYBOARD = 0x1 << 3;
112 
113     /**
114      * No video - no animated frames > 1fps.
115      */
116     @AddedInOrBefore(majorVersion = 33)
117     public static final int UX_RESTRICTIONS_NO_VIDEO = 0x1 << 4;
118 
119     /**
120      * Limit the number of items user can browse through in total in a single task.
121      *
122      * <p>Refer to {@link #getMaxCumulativeContentItems()} and
123      * {@link #getMaxContentDepth()} for the upper bounds on content
124      * serving.
125      */
126     @AddedInOrBefore(majorVersion = 33)
127     public static final int UX_RESTRICTIONS_LIMIT_CONTENT = 0x1 << 5;
128 
129     /**
130      * No setup that requires form entry or interaction with external devices.
131      */
132     @AddedInOrBefore(majorVersion = 33)
133     public static final int UX_RESTRICTIONS_NO_SETUP = 0x1 << 6;
134 
135     /**
136      * No Text Message (SMS, email, conversational, etc.)
137      */
138     @AddedInOrBefore(majorVersion = 33)
139     public static final int UX_RESTRICTIONS_NO_TEXT_MESSAGE = 0x1 << 7;
140 
141     /**
142      * No text transcription (live or leave behind) of voice can be shown.
143      */
144     @AddedInOrBefore(majorVersion = 33)
145     public static final int UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION = 0x1 << 8;
146 
147     /**
148      * All restrictions are in effect.
149      */
150     @AddedInOrBefore(majorVersion = 33)
151     public static final int UX_RESTRICTIONS_FULLY_RESTRICTED =
152             UX_RESTRICTIONS_NO_DIALPAD | UX_RESTRICTIONS_NO_FILTERING
153                     | UX_RESTRICTIONS_LIMIT_STRING_LENGTH | UX_RESTRICTIONS_NO_KEYBOARD
154                     | UX_RESTRICTIONS_NO_VIDEO | UX_RESTRICTIONS_LIMIT_CONTENT
155                     | UX_RESTRICTIONS_NO_SETUP | UX_RESTRICTIONS_NO_TEXT_MESSAGE
156                     | UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION;
157 
158     @IntDef(flag = true,
159             prefix = {"UX_RESTRICTIONS_"},
160             value = {UX_RESTRICTIONS_BASELINE,
161                     UX_RESTRICTIONS_NO_DIALPAD,
162                     UX_RESTRICTIONS_NO_FILTERING,
163                     UX_RESTRICTIONS_LIMIT_STRING_LENGTH,
164                     UX_RESTRICTIONS_NO_KEYBOARD,
165                     UX_RESTRICTIONS_NO_VIDEO,
166                     UX_RESTRICTIONS_LIMIT_CONTENT,
167                     UX_RESTRICTIONS_NO_SETUP,
168                     UX_RESTRICTIONS_NO_TEXT_MESSAGE,
169                     UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION})
170     @Retention(RetentionPolicy.SOURCE)
171     public @interface CarUxRestrictionsInfo {
172     }
173 
174     private final long mTimeStamp;
175     private final boolean mRequiresDistractionOptimization;
176     @CarUxRestrictionsInfo
177     private final int mActiveRestrictions;
178     // Restriction Parameters
179     private final int mMaxStringLength;
180     private final int mMaxCumulativeContentItems;
181     private final int mMaxContentDepth;
182 
183     /**
184      * Builder class for {@link CarUxRestrictions}
185      */
186     public static class Builder {
187         private final long mTimeStamp;
188         private final boolean mRequiresDistractionOptimization;
189         @CarUxRestrictionsInfo
190         private final int mActiveRestrictions;
191         // Restriction Parameters
192         private int mMaxStringLength = DEFAULT_MAX_LENGTH;
193         private int mMaxCumulativeContentItems = DEFAULT_MAX_CUMULATIVE_ITEMS;
194         private int mMaxContentDepth = DEFAULT_MAX_CONTENT_DEPTH;
195 
Builder(boolean reqOpt, @CarUxRestrictionsInfo int restrictions, long time)196         public Builder(boolean reqOpt, @CarUxRestrictionsInfo int restrictions, long time) {
197             mRequiresDistractionOptimization = reqOpt;
198             mActiveRestrictions = restrictions;
199             mTimeStamp = time;
200         }
201 
202         /**
203          * Set the maximum length of general purpose strings that can be displayed when
204          * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_STRING_LENGTH} is imposed.
205          */
206         @AddedInOrBefore(majorVersion = 33)
setMaxStringLength(int length)207         public Builder setMaxStringLength(int length) {
208             mMaxStringLength = length;
209             return this;
210         }
211 
212         /**
213          *  Set the maximum number of cumulative content items that can be displayed when
214          * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
215          */
216         @AddedInOrBefore(majorVersion = 33)
setMaxCumulativeContentItems(int number)217         public Builder setMaxCumulativeContentItems(int number) {
218             mMaxCumulativeContentItems = number;
219             return this;
220         }
221 
222         /**
223          * Set the maximum number of levels that the user can navigate to when
224          * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
225          */
226         @AddedInOrBefore(majorVersion = 33)
setMaxContentDepth(int depth)227         public Builder setMaxContentDepth(int depth) {
228             mMaxContentDepth = depth;
229             return this;
230         }
231 
232         /**
233          * Build and return the {@link CarUxRestrictions} object
234          */
235         @AddedInOrBefore(majorVersion = 33)
build()236         public CarUxRestrictions build() {
237             return new CarUxRestrictions(this);
238         }
239 
240     }
241 
242     /**
243      * Time at which this UX restriction event was deduced based on the car's driving state.
244      *
245      * @return Elapsed time in nanoseconds since system boot.
246      *
247      * @hide
248      */
249     @AddedInOrBefore(majorVersion = 33)
getTimeStamp()250     public long getTimeStamp() {
251         return mTimeStamp;
252     }
253 
254     /**
255      * Conveys if the foreground activity needs to be distraction optimized.
256      * Activities that can handle distraction optimization need to be tagged as a distraction
257      * optimized in the app's manifest.
258      * <p>
259      * If the app has a foreground activity that has not been distraction optimized, the app has
260      * to switch to another activity that is distraction optimized.  Failing that, the system will
261      * stop the foreground activity.
262      *
263      * @return true if distraction optimization is required, false if not
264      */
265     @AddedInOrBefore(majorVersion = 33)
isRequiresDistractionOptimization()266     public boolean isRequiresDistractionOptimization() {
267         return mRequiresDistractionOptimization;
268     }
269 
270     /**
271      * A combination of the Car UX Restrictions that is active for the current state of driving.
272      *
273      * @return A combination of the above {@code @CarUxRestrictionsInfo}
274      */
275     @CarUxRestrictionsInfo
276     @AddedInOrBefore(majorVersion = 33)
getActiveRestrictions()277     public int getActiveRestrictions() {
278         return mActiveRestrictions;
279     }
280 
281     /**
282      * Get the maximum length of general purpose strings that can be displayed when
283      * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_STRING_LENGTH} is imposed.
284      *
285      * @return the maximum length of string that can be displayed
286      */
287     @AddedInOrBefore(majorVersion = 33)
getMaxRestrictedStringLength()288     public int getMaxRestrictedStringLength() {
289         return mMaxStringLength;
290     }
291 
292     /**
293      * Get the maximum allowable number of content items that can be displayed to a user during
294      * traversal through any one path in a single task, when
295      * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
296      * <p>
297      * For example, if a task involving only one view, this represents the maximum allowable number
298      * of content items in this single view.
299      * <p>
300      * However, if the task involves selection of a content item in an originating view that then
301      * surfaces a secondary view to the user, then this value represents the maximum allowable
302      * number of content items between the originating and secondary views combined.
303      * <p>
304      * Specifically, if the maximum allowable value was 60 and a task involved browsing a list of
305      * countries and then viewing the top songs within a country, it would be acceptable to do
306      * either of the following:
307      * <ul>
308      * <li> list 10 countries, and then display the top 50 songs after country selection, or
309      * <li> list 20 countries, and then display the top 40 songs after country selection.
310      * </ul>
311      * <p>
312      * Please refer to this and {@link #getMaxContentDepth()} to know the upper bounds on the
313      * content display when the restriction is in place.
314      *
315      * @return maximum number of cumulative items that can be displayed
316      */
317     @AddedInOrBefore(majorVersion = 33)
getMaxCumulativeContentItems()318     public int getMaxCumulativeContentItems() {
319         return mMaxCumulativeContentItems;
320     }
321 
322     /**
323      * Get the maximum allowable number of content depth levels or view traversals through any one
324      * path in a single task.  This is applicable when
325      * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed.
326      * <p>
327      * For example, if a task involves only selecting an item from a single list on one view,
328      * the task's content depth would be considered 1.
329      * <p>
330      * However, if the task involves selection of a content item in an originating view that then
331      * surfaces a secondary view to the user, the task's content depth would be considered 2.
332      * <p>
333      * Specifically, if a task involved browsing a list of countries, selecting a genre within the
334      * country, and then viewing the top songs within a country, the task's content depth would be
335      * considered 3.
336      * <p>
337      * Please refer to this and {@link #getMaxCumulativeContentItems()} to know the upper bounds on
338      * the content display when the restriction is in place.
339      *
340      * @return maximum number of cumulative items that can be displayed
341      */
342     @AddedInOrBefore(majorVersion = 33)
getMaxContentDepth()343     public int getMaxContentDepth() {
344         return mMaxContentDepth;
345     }
346 
347     @Override
348     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
349     @AddedInOrBefore(majorVersion = 33)
describeContents()350     public int describeContents() {
351         return 0;
352     }
353 
354     @Override
355     @AddedInOrBefore(majorVersion = 33)
writeToParcel(Parcel dest, int flags)356     public void writeToParcel(Parcel dest, int flags) {
357         dest.writeInt(mActiveRestrictions);
358         dest.writeLong(mTimeStamp);
359         dest.writeInt(mRequiresDistractionOptimization ? 1 : 0);
360         dest.writeInt(mMaxStringLength);
361         dest.writeInt(mMaxCumulativeContentItems);
362         dest.writeInt(mMaxContentDepth);
363     }
364 
365     @AddedInOrBefore(majorVersion = 33)
366     public static final Parcelable.Creator<CarUxRestrictions> CREATOR =
367             new Parcelable.Creator<CarUxRestrictions>() {
368         @Override
369         public CarUxRestrictions createFromParcel(Parcel in) {
370             return new CarUxRestrictions(in);
371         }
372 
373         @Override
374         public CarUxRestrictions[] newArray(int size) {
375             return new CarUxRestrictions[size];
376         }
377     };
378 
CarUxRestrictions(CarUxRestrictions uxRestrictions)379     public CarUxRestrictions(CarUxRestrictions uxRestrictions) {
380         mTimeStamp = uxRestrictions.getTimeStamp();
381         mRequiresDistractionOptimization = uxRestrictions.isRequiresDistractionOptimization();
382         mActiveRestrictions = uxRestrictions.getActiveRestrictions();
383         mMaxStringLength = uxRestrictions.mMaxStringLength;
384         mMaxCumulativeContentItems = uxRestrictions.mMaxCumulativeContentItems;
385         mMaxContentDepth = uxRestrictions.mMaxContentDepth;
386     }
387 
CarUxRestrictions(Builder builder)388     private CarUxRestrictions(Builder builder) {
389         mTimeStamp = builder.mTimeStamp;
390         mActiveRestrictions = builder.mActiveRestrictions;
391         mRequiresDistractionOptimization = builder.mRequiresDistractionOptimization;
392         mMaxStringLength = builder.mMaxStringLength;
393         mMaxCumulativeContentItems = builder.mMaxCumulativeContentItems;
394         mMaxContentDepth = builder.mMaxContentDepth;
395     }
396 
CarUxRestrictions(Parcel in)397     private CarUxRestrictions(Parcel in) {
398         mActiveRestrictions = in.readInt();
399         mTimeStamp = in.readLong();
400         mRequiresDistractionOptimization = in.readInt() != 0;
401         mMaxStringLength = in.readInt();
402         mMaxCumulativeContentItems = in.readInt();
403         mMaxContentDepth = in.readInt();
404     }
405 
406     @Override
407     @AddedInOrBefore(majorVersion = 33)
toString()408     public String toString() {
409         return "DO: " + mRequiresDistractionOptimization + " UxR: " + mActiveRestrictions
410                 + " time: " + mTimeStamp;
411     }
412 
413     /**
414      * Compares if the restrictions are the same.  Doesn't compare the timestamps.
415      *
416      * @param other the other CarUxRestrictions object
417      * @return true if the restrictions are same, false otherwise
418      */
419     @AddedInOrBefore(majorVersion = 33)
isSameRestrictions(CarUxRestrictions other)420     public boolean isSameRestrictions(CarUxRestrictions other) {
421         if (other == null) {
422             return false;
423         }
424         if (other == this) {
425             return true;
426         }
427         return other.mRequiresDistractionOptimization == mRequiresDistractionOptimization
428                 && other.mActiveRestrictions == mActiveRestrictions;
429     }
430 }
431