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