/* * 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. *

* The restriction information is organized as follows: *

*

* Apps that intend to be run when the car is being driven need to *

*/ 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 with alpha-numeric character via the use of a character entry method. * * For example, do not allow entering a letter to filter the content of a list down to * items only containing that letter. */ 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 or other manual text string entry actvities. */ 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 user can browse through in total in a single task. * *

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 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. * * @hide */ 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. *

* 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. *

* For example, if a task involving only one view, this represents the maximum allowable number * of content items in this single view. *

* 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. *

* 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: *

*

* 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. *

* 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. *

* 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. *

* 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. *

* 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 CREATOR = new Parcelable.Creator() { @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; } }