| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.car.drivingstate; |
| |
| import android.annotation.IntDef; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| |
| /** |
| * Car UX Restrictions event. This contains information on the set of UX restrictions that is in |
| * place due to the car's driving state. |
| * <p> |
| * The restriction information is organized as follows: |
| * <ul> |
| * <li> When there are no restrictions in place, for example when the car is parked, |
| * <ul> |
| * <li> {@link #isRequiresDistractionOptimization()} returns false. Apps can display activities |
| * that are not distraction optimized. |
| * <li> When {@link #isRequiresDistractionOptimization()} returns false, apps don't have to call |
| * {@link #getActiveRestrictions()}, since there is no distraction optimization required. |
| * </ul> |
| * <li> When the driving state changes, causing the UX restrictions to come in effect, |
| * <ul> |
| * <li> {@link #isRequiresDistractionOptimization()} returns true. Apps can only display activities |
| * that are distraction optimized. Distraction optimized activities must follow the base design |
| * guidelines to ensure a distraction free driving experience for the user. |
| * <li> When {@link #isRequiresDistractionOptimization()} returns true, apps must call |
| * {@link #getActiveRestrictions()}, to get the currently active UX restrictions to adhere to. |
| * {@link #getActiveRestrictions()} provides additional information on the set of UX |
| * restrictions that are in place for the current driving state. |
| * <p> |
| * The UX restrictions returned by {@link #getActiveRestrictions()}, for the same driving state of |
| * the vehicle, could vary depending on the OEM and the market. For example, when the car is |
| * idling, the set of active UX restrictions will depend on the car maker and the safety standards |
| * of the market that the vehicle is deployed in. |
| * </ul> |
| * </ul> |
| * <p> |
| * Apps that intend to be run when the car is being driven need to |
| * <ul> |
| * <li> Comply with the general distraction optimization guidelines. |
| * <li> Listen and react to the UX restrictions changes as detailed above. Since the restrictions |
| * could vary depending on the market, apps are expected to react to the restriction information |
| * and not to the absolute driving state. |
| * </ul> |
| */ |
| public final class CarUxRestrictions implements Parcelable { |
| |
| // Default fallback values for the restriction related parameters if the information is |
| // not available from the underlying service. |
| private static final int DEFAULT_MAX_LENGTH = 120; |
| private static final int DEFAULT_MAX_CUMULATIVE_ITEMS = 21; |
| private static final int DEFAULT_MAX_CONTENT_DEPTH = 3; |
| |
| /** |
| * No specific restrictions in place, but baseline distraction optimization guidelines need to |
| * be adhered to when {@link #isRequiresDistractionOptimization()} is true. |
| */ |
| public static final int UX_RESTRICTIONS_BASELINE = 0; |
| |
| // Granular UX Restrictions that are imposed when distraction optimization is required. |
| /** |
| * No dialpad for the purpose of initiating a phone call. |
| */ |
| public static final int UX_RESTRICTIONS_NO_DIALPAD = 1; |
| |
| /** |
| * No filtering a list. |
| */ |
| public static final int UX_RESTRICTIONS_NO_FILTERING = 0x1 << 1; |
| |
| /** |
| * General purpose strings length cannot exceed the character limit provided by |
| * {@link #getMaxRestrictedStringLength()} |
| */ |
| public static final int UX_RESTRICTIONS_LIMIT_STRING_LENGTH = 0x1 << 2; |
| |
| /** |
| * No text entry for the purpose of searching etc. |
| */ |
| public static final int UX_RESTRICTIONS_NO_KEYBOARD = 0x1 << 3; |
| |
| /** |
| * No video - no animated frames > 1fps. |
| */ |
| public static final int UX_RESTRICTIONS_NO_VIDEO = 0x1 << 4; |
| |
| /** |
| * Limit the number of items displayed on the screen. |
| * Refer to {@link #getMaxCumulativeContentItems()} and |
| * {@link #getMaxContentDepth()} for the upper bounds on content |
| * serving. |
| */ |
| public static final int UX_RESTRICTIONS_LIMIT_CONTENT = 0x1 << 5; |
| |
| /** |
| * No setup that requires form entry or interaction with external devices. |
| */ |
| public static final int UX_RESTRICTIONS_NO_SETUP = 0x1 << 6; |
| |
| /** |
| * No Text Message (SMS, email, conversational, etc.) |
| */ |
| public static final int UX_RESTRICTIONS_NO_TEXT_MESSAGE = 0x1 << 7; |
| |
| /** |
| * No text transcription (live or leave behind) of voice can be shown. |
| */ |
| public static final int UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION = 0x1 << 8; |
| |
| |
| /** |
| * All the above restrictions are in effect. |
| */ |
| public static final int UX_RESTRICTIONS_FULLY_RESTRICTED = |
| UX_RESTRICTIONS_NO_DIALPAD | UX_RESTRICTIONS_NO_FILTERING |
| | UX_RESTRICTIONS_LIMIT_STRING_LENGTH | UX_RESTRICTIONS_NO_KEYBOARD |
| | UX_RESTRICTIONS_NO_VIDEO | UX_RESTRICTIONS_LIMIT_CONTENT |
| | UX_RESTRICTIONS_NO_SETUP | UX_RESTRICTIONS_NO_TEXT_MESSAGE |
| | UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION; |
| |
| @IntDef(flag = true, |
| prefix = {"UX_RESTRICTIONS_"}, |
| value = {UX_RESTRICTIONS_BASELINE, |
| UX_RESTRICTIONS_NO_DIALPAD, |
| UX_RESTRICTIONS_NO_FILTERING, |
| UX_RESTRICTIONS_LIMIT_STRING_LENGTH, |
| UX_RESTRICTIONS_NO_KEYBOARD, |
| UX_RESTRICTIONS_NO_VIDEO, |
| UX_RESTRICTIONS_LIMIT_CONTENT, |
| UX_RESTRICTIONS_NO_SETUP, |
| UX_RESTRICTIONS_NO_TEXT_MESSAGE, |
| UX_RESTRICTIONS_NO_VOICE_TRANSCRIPTION}) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface CarUxRestrictionsInfo { |
| } |
| |
| private final long mTimeStamp; |
| private final boolean mRequiresDistractionOptimization; |
| @CarUxRestrictionsInfo |
| private final int mActiveRestrictions; |
| // Restriction Parameters |
| private final int mMaxStringLength; |
| private final int mMaxCumulativeContentItems; |
| private final int mMaxContentDepth; |
| |
| /** |
| * Builder class for {@link CarUxRestrictions} |
| */ |
| public static class Builder { |
| private final long mTimeStamp; |
| private final boolean mRequiresDistractionOptimization; |
| @CarUxRestrictionsInfo |
| private final int mActiveRestrictions; |
| // Restriction Parameters |
| private int mMaxStringLength = DEFAULT_MAX_LENGTH; |
| private int mMaxCumulativeContentItems = DEFAULT_MAX_CUMULATIVE_ITEMS; |
| private int mMaxContentDepth = DEFAULT_MAX_CONTENT_DEPTH; |
| |
| public Builder(boolean reqOpt, @CarUxRestrictionsInfo int restrictions, long time) { |
| mRequiresDistractionOptimization = reqOpt; |
| mActiveRestrictions = restrictions; |
| mTimeStamp = time; |
| } |
| |
| /** |
| * Set the maximum length of general purpose strings that can be displayed when |
| * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_STRING_LENGTH} is imposed. |
| */ |
| public Builder setMaxStringLength(int length) { |
| mMaxStringLength = length; |
| return this; |
| } |
| |
| /** |
| * Set the maximum number of cumulative content items that can be displayed when |
| * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed. |
| */ |
| public Builder setMaxCumulativeContentItems(int number) { |
| mMaxCumulativeContentItems = number; |
| return this; |
| } |
| |
| /** |
| * Set the maximum number of levels that the user can navigate to when |
| * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed. |
| */ |
| public Builder setMaxContentDepth(int depth) { |
| mMaxContentDepth = depth; |
| return this; |
| } |
| |
| /** |
| * Build and return the {@link CarUxRestrictions} object |
| */ |
| public CarUxRestrictions build() { |
| return new CarUxRestrictions(this); |
| } |
| |
| } |
| |
| /** |
| * Time at which this UX restriction event was deduced based on the car's driving state. |
| * |
| * @return Elapsed time in nanoseconds since system boot. |
| */ |
| public long getTimeStamp() { |
| return mTimeStamp; |
| } |
| |
| /** |
| * Conveys if the foreground activity needs to be distraction optimized. |
| * Activities that can handle distraction optimization need to be tagged as a distraction |
| * optimized in the app's manifest. |
| * <p> |
| * If the app has a foreground activity that has not been distraction optimized, the app has |
| * to switch to another activity that is distraction optimized. Failing that, the system will |
| * stop the foreground activity. |
| * |
| * @return true if distraction optimization is required, false if not |
| */ |
| public boolean isRequiresDistractionOptimization() { |
| return mRequiresDistractionOptimization; |
| } |
| |
| /** |
| * A combination of the Car UX Restrictions that is active for the current state of driving. |
| * |
| * @return A combination of the above {@code @CarUxRestrictionsInfo} |
| */ |
| @CarUxRestrictionsInfo |
| public int getActiveRestrictions() { |
| return mActiveRestrictions; |
| } |
| |
| /** |
| * Get the maximum length of general purpose strings that can be displayed when |
| * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_STRING_LENGTH} is imposed. |
| * |
| * @return the maximum length of string that can be displayed |
| */ |
| public int getMaxRestrictedStringLength() { |
| return mMaxStringLength; |
| } |
| |
| /** |
| * Get the maximum allowable number of content items that can be displayed to a user during |
| * traversal through any one path in a single task, when |
| * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed. |
| * <p> |
| * For example, if a task involving only one view, this represents the maximum allowable number |
| * of content items in this single view. |
| * <p> |
| * However, if the task involves selection of a content item in an originating view that then |
| * surfaces a secondary view to the user, then this value represents the maximum allowable |
| * number of content items between the originating and secondary views combined. |
| * <p> |
| * Specifically, if the maximum allowable value was 60 and a task involved browsing a list of |
| * countries and then viewing the top songs within a country, it would be acceptable to do |
| * either of the following: |
| * <ul> |
| * <li> list 10 countries, and then display the top 50 songs after country selection, or |
| * <li> list 20 countries, and then display the top 40 songs after country selection. |
| * </ul> |
| * <p> |
| * Please refer to this and {@link #getMaxContentDepth()} to know the upper bounds on the |
| * content display when the restriction is in place. |
| * |
| * @return maximum number of cumulative items that can be displayed |
| */ |
| public int getMaxCumulativeContentItems() { |
| return mMaxCumulativeContentItems; |
| } |
| |
| /** |
| * Get the maximum allowable number of content depth levels or view traversals through any one |
| * path in a single task. This is applicable when |
| * {@link CarUxRestrictions#UX_RESTRICTIONS_LIMIT_CONTENT} is imposed. |
| * <p> |
| * For example, if a task involves only selecting an item from a single list on one view, |
| * the task's content depth would be considered 1. |
| * <p> |
| * However, if the task involves selection of a content item in an originating view that then |
| * surfaces a secondary view to the user, the task's content depth would be considered 2. |
| * <p> |
| * Specifically, if a task involved browsing a list of countries, selecting a genre within the |
| * country, and then viewing the top songs within a country, the task's content depth would be |
| * considered 3. |
| * <p> |
| * Please refer to this and {@link #getMaxCumulativeContentItems()} to know the upper bounds on |
| * the content display when the restriction is in place. |
| * |
| * @return maximum number of cumulative items that can be displayed |
| */ |
| public int getMaxContentDepth() { |
| return mMaxContentDepth; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(Parcel dest, int flags) { |
| dest.writeInt(mActiveRestrictions); |
| dest.writeLong(mTimeStamp); |
| dest.writeInt(mRequiresDistractionOptimization ? 1 : 0); |
| dest.writeInt(mMaxStringLength); |
| dest.writeInt(mMaxCumulativeContentItems); |
| dest.writeInt(mMaxContentDepth); |
| } |
| |
| public static final Parcelable.Creator<CarUxRestrictions> CREATOR = |
| new Parcelable.Creator<CarUxRestrictions>() { |
| @Override |
| public CarUxRestrictions createFromParcel(Parcel in) { |
| return new CarUxRestrictions(in); |
| } |
| |
| @Override |
| public CarUxRestrictions[] newArray(int size) { |
| return new CarUxRestrictions[size]; |
| } |
| }; |
| |
| public CarUxRestrictions(CarUxRestrictions uxRestrictions) { |
| mTimeStamp = uxRestrictions.getTimeStamp(); |
| mRequiresDistractionOptimization = uxRestrictions.isRequiresDistractionOptimization(); |
| mActiveRestrictions = uxRestrictions.getActiveRestrictions(); |
| mMaxStringLength = uxRestrictions.mMaxStringLength; |
| mMaxCumulativeContentItems = uxRestrictions.mMaxCumulativeContentItems; |
| mMaxContentDepth = uxRestrictions.mMaxContentDepth; |
| } |
| |
| private CarUxRestrictions(Builder builder) { |
| mTimeStamp = builder.mTimeStamp; |
| mActiveRestrictions = builder.mActiveRestrictions; |
| mRequiresDistractionOptimization = builder.mRequiresDistractionOptimization; |
| mMaxStringLength = builder.mMaxStringLength; |
| mMaxCumulativeContentItems = builder.mMaxCumulativeContentItems; |
| mMaxContentDepth = builder.mMaxContentDepth; |
| } |
| |
| private CarUxRestrictions(Parcel in) { |
| mActiveRestrictions = in.readInt(); |
| mTimeStamp = in.readLong(); |
| mRequiresDistractionOptimization = in.readInt() != 0; |
| mMaxStringLength = in.readInt(); |
| mMaxCumulativeContentItems = in.readInt(); |
| mMaxContentDepth = in.readInt(); |
| } |
| |
| @Override |
| public String toString() { |
| return "DO: " + mRequiresDistractionOptimization + " UxR: " + mActiveRestrictions |
| + " time: " + mTimeStamp; |
| } |
| |
| /** |
| * Compares if the restrictions are the same. Doesn't compare the timestamps. |
| * |
| * @param other the other CarUxRestrictions object |
| * @return true if the restrictions are same, false otherwise |
| */ |
| public boolean isSameRestrictions(CarUxRestrictions other) { |
| if (other == null) { |
| return false; |
| } |
| if (other == this) { |
| return true; |
| } |
| return other.mRequiresDistractionOptimization == mRequiresDistractionOptimization |
| && other.mActiveRestrictions == mActiveRestrictions; |
| } |
| } |