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