blob: 2ed7463742f89e9695f3e53310deba74df44eb2a [file] [log] [blame]
/*
* Copyright (C) 2022 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.safetycenter.config;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.SystemApi;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.RequiresApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Data class used to represent the initial configuration of a safety source
*
* @hide
*/
@SystemApi
@RequiresApi(TIRAMISU)
public final class SafetySource implements Parcelable {
/** Static safety source. */
public static final int SAFETY_SOURCE_TYPE_STATIC = 1;
/** Dynamic safety source. */
public static final int SAFETY_SOURCE_TYPE_DYNAMIC = 2;
/** Issue only safety source. */
public static final int SAFETY_SOURCE_TYPE_ISSUE_ONLY = 3;
/**
* All possible safety source types.
*
* @hide
*/
@IntDef(prefix = {"SAFETY_SOURCE_TYPE_"}, value = {
SAFETY_SOURCE_TYPE_STATIC,
SAFETY_SOURCE_TYPE_DYNAMIC,
SAFETY_SOURCE_TYPE_ISSUE_ONLY
})
@Retention(RetentionPolicy.SOURCE)
public @interface SafetySourceType {
}
/** Profile property unspecified. */
public static final int PROFILE_NONE = 0;
/**
* Even when the active user has managed profiles, the safety source will be displayed as a
* single entry for the primary profile.
*/
public static final int PROFILE_PRIMARY = 1;
/**
* When the user has managed profiles, the safety source will be displayed as multiple entries
* one for each profile.
*/
public static final int PROFILE_ALL = 2;
/**
* All possible profile configurations for a safety source.
*
* @hide
*/
@IntDef(prefix = {"PROFILE_"}, value = {
PROFILE_NONE,
PROFILE_PRIMARY,
PROFILE_ALL
})
@Retention(RetentionPolicy.SOURCE)
public @interface Profile {
}
/** This dynamic source will create an enabled entry in the UI until an update is received. */
public static final int INITIAL_DISPLAY_STATE_ENABLED = 0;
/** This dynamic source will create a disabled entry in the UI until an update is received. */
public static final int INITIAL_DISPLAY_STATE_DISABLED = 1;
/** This dynamic source will have no entry in the UI until an update is received. */
public static final int INITIAL_DISPLAY_STATE_HIDDEN = 2;
/**
* All possible initial display states for a dynamic safety source.
*
* @hide
*/
@IntDef(prefix = {"INITIAL_DISPLAY_STATE_"}, value = {
INITIAL_DISPLAY_STATE_ENABLED,
INITIAL_DISPLAY_STATE_DISABLED,
INITIAL_DISPLAY_STATE_HIDDEN
})
@Retention(RetentionPolicy.SOURCE)
public @interface InitialDisplayState {
}
@SafetySourceType
private final int mType;
@NonNull
private final String mId;
@Nullable
private final String mPackageName;
@StringRes
private final int mTitleResId;
@StringRes
private final int mTitleForWorkResId;
@StringRes
private final int mSummaryResId;
@Nullable
private final String mIntentAction;
@Profile
private final int mProfile;
@InitialDisplayState
private final int mInitialDisplayState;
private final int mMaxSeverityLevel;
@StringRes
private final int mSearchTermsResId;
@Nullable
private final String mBroadcastReceiverClassName;
private final boolean mLoggingAllowed;
private final boolean mRefreshOnPageOpenAllowed;
/** Returns the id of this safety source. */
private SafetySource(
@SafetySourceType int type,
@NonNull String id,
@Nullable String packageName,
@StringRes int titleResId,
@StringRes int titleForWorkResId,
@StringRes int summaryResId,
@Nullable String intentAction,
@Profile int profile,
@InitialDisplayState int initialDisplayState,
int maxSeverityLevel,
@StringRes int searchTermsResId,
@Nullable String broadcastReceiverClassName,
boolean loggingAllowed,
boolean refreshOnPageOpenAllowed) {
mType = type;
mId = id;
mPackageName = packageName;
mTitleResId = titleResId;
mTitleForWorkResId = titleForWorkResId;
mSummaryResId = summaryResId;
mIntentAction = intentAction;
mProfile = profile;
mInitialDisplayState = initialDisplayState;
mMaxSeverityLevel = maxSeverityLevel;
mSearchTermsResId = searchTermsResId;
mBroadcastReceiverClassName = broadcastReceiverClassName;
mLoggingAllowed = loggingAllowed;
mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed;
}
/** Returns the type of this safety source. */
@SafetySourceType
public int getType() {
return mType;
}
/** Returns the id of this safety source. */
@NonNull
public String getId() {
return mId;
}
/** Returns the package name of this safety source. */
@NonNull
public String getPackageName() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
throw new UnsupportedOperationException(
"getPackageName unsupported for static safety source");
}
return mPackageName;
}
/** Returns the resource id of the title of this safety source. */
@StringRes
public int getTitleResId() {
if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new UnsupportedOperationException(
"getTitleResId unsupported for issue only safety source");
}
return mTitleResId;
}
/** Returns the resource id of the title for work of this safety source. */
@StringRes
public int getTitleForWorkResId() {
if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new UnsupportedOperationException(
"getTitleForWorkResId unsupported for issue only safety source");
}
if (mProfile == PROFILE_PRIMARY) {
throw new UnsupportedOperationException(
"getTitleForWorkResId unsupported for primary profile safety source");
}
return mTitleForWorkResId;
}
/** Returns the resource id of the summary of this safety source. */
@StringRes
public int getSummaryResId() {
if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new UnsupportedOperationException(
"getSummaryResId unsupported for issue only safety source");
}
return mSummaryResId;
}
/** Returns the intent action of this safety source. */
@Nullable
public String getIntentAction() {
if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new UnsupportedOperationException(
"getIntentAction unsupported for issue only safety source");
}
return mIntentAction;
}
/** Returns the profile property of this safety source. */
@Profile
public int getProfile() {
return mProfile;
}
/** Returns the initial display state of this safety source. */
@InitialDisplayState
public int getInitialDisplayState() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
throw new UnsupportedOperationException(
"getInitialDisplayState unsupported for static safety source");
}
if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new UnsupportedOperationException(
"getInitialDisplayState unsupported for issue only safety source");
}
return mInitialDisplayState;
}
/** Returns the maximum severity level of this safety source. */
public int getMaxSeverityLevel() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
throw new UnsupportedOperationException(
"getMaxSeverityLevel unsupported for static safety source");
}
return mMaxSeverityLevel;
}
/**
* Returns the resource id of the search terms of this safety source if set; otherwise
* {@link Resources#ID_NULL}.
*/
@StringRes
public int getSearchTermsResId() {
if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new UnsupportedOperationException(
"getSearchTermsResId unsupported for issue only safety source");
}
return mSearchTermsResId;
}
/** Returns the broadcast receiver class name of this safety source. */
@Nullable
public String getBroadcastReceiverClassName() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
throw new UnsupportedOperationException(
"getBroadcastReceiverClassName unsupported for static safety source");
}
return mBroadcastReceiverClassName;
}
/** Returns the logging allowed property of this safety source. */
public boolean isLoggingAllowed() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
throw new UnsupportedOperationException(
"isLoggingAllowed unsupported for static safety source");
}
return mLoggingAllowed;
}
/** Returns the refresh on page open allowed property of this safety source. */
public boolean isRefreshOnPageOpenAllowed() {
if (mType == SAFETY_SOURCE_TYPE_STATIC) {
throw new UnsupportedOperationException(
"isRefreshOnPageOpenAllowed unsupported for static safety source");
}
return mRefreshOnPageOpenAllowed;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SafetySource)) return false;
SafetySource that = (SafetySource) o;
return mType == that.mType
&& Objects.equals(mId, that.mId)
&& Objects.equals(mPackageName, that.mPackageName)
&& mTitleResId == that.mTitleResId
&& mTitleForWorkResId == that.mTitleForWorkResId
&& mSummaryResId == that.mSummaryResId
&& Objects.equals(mIntentAction, that.mIntentAction)
&& mProfile == that.mProfile
&& mInitialDisplayState == that.mInitialDisplayState
&& mMaxSeverityLevel == that.mMaxSeverityLevel
&& mSearchTermsResId == that.mSearchTermsResId
&& Objects.equals(mBroadcastReceiverClassName, that.mBroadcastReceiverClassName)
&& mLoggingAllowed == that.mLoggingAllowed
&& mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed;
}
@Override
public int hashCode() {
return Objects.hash(mType, mId, mPackageName, mTitleResId, mTitleForWorkResId,
mSummaryResId, mIntentAction, mProfile, mInitialDisplayState, mMaxSeverityLevel,
mSearchTermsResId, mBroadcastReceiverClassName, mLoggingAllowed,
mRefreshOnPageOpenAllowed);
}
@Override
public String toString() {
return "SafetySource{"
+ "mType=" + mType
+ ", mId='" + mId + '\''
+ ", mPackageName='" + mPackageName + '\''
+ ", mTitleResId=" + mTitleResId
+ ", mTitleForWorkResId=" + mTitleForWorkResId
+ ", mSummaryResId=" + mSummaryResId
+ ", mIntentAction='" + mIntentAction + '\''
+ ", mProfile=" + mProfile
+ ", mInitialDisplayState=" + mInitialDisplayState
+ ", mMaxSeverityLevel=" + mMaxSeverityLevel
+ ", mSearchTermsResId=" + mSearchTermsResId
+ ", mBroadcastReceiverClassName='" + mBroadcastReceiverClassName + '\''
+ ", mLoggingAllowed=" + mLoggingAllowed
+ ", mRefreshOnPageOpenAllowed=" + mRefreshOnPageOpenAllowed
+ '}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mType);
dest.writeString(mId);
dest.writeString(mPackageName);
dest.writeInt(mTitleResId);
dest.writeInt(mTitleForWorkResId);
dest.writeInt(mSummaryResId);
dest.writeString(mIntentAction);
dest.writeInt(mProfile);
dest.writeInt(mInitialDisplayState);
dest.writeInt(mMaxSeverityLevel);
dest.writeInt(mSearchTermsResId);
dest.writeString(mBroadcastReceiverClassName);
dest.writeBoolean(mLoggingAllowed);
dest.writeBoolean(mRefreshOnPageOpenAllowed);
}
@NonNull
public static final Parcelable.Creator<SafetySource> CREATOR =
new Parcelable.Creator<SafetySource>() {
@Override
public SafetySource createFromParcel(Parcel in) {
return new Builder(in.readInt())
.setId(in.readString())
.setPackageName(in.readString())
.setTitleResId(in.readInt())
.setTitleForWorkResId(in.readInt())
.setSummaryResId(in.readInt())
.setIntentAction(in.readString())
.setProfile(in.readInt())
.setInitialDisplayState(in.readInt())
.setMaxSeverityLevel(in.readInt())
.setSearchTermsResId(in.readInt())
.setBroadcastReceiverClassName(in.readString())
.setLoggingAllowed(in.readBoolean())
.setRefreshOnPageOpenAllowed(in.readBoolean())
.build();
}
@Override
public SafetySource[] newArray(int size) {
return new SafetySource[size];
}
};
/** Builder class for {@link SafetySource}. */
public static final class Builder {
@SafetySourceType
private final int mType;
@Nullable
private String mId;
@Nullable
private String mPackageName;
@Nullable
@StringRes
private Integer mTitleResId;
@Nullable
@StringRes
private Integer mTitleForWorkResId;
@Nullable
@StringRes
private Integer mSummaryResId;
@Nullable
private String mIntentAction;
@Nullable
@Profile
private Integer mProfile;
@Nullable
@InitialDisplayState
private Integer mInitialDisplayState;
@Nullable
private Integer mMaxSeverityLevel;
@Nullable
@StringRes
private Integer mSearchTermsResId;
@Nullable
private String mBroadcastReceiverClassName;
@Nullable
private Boolean mLoggingAllowed;
@Nullable
private Boolean mRefreshOnPageOpenAllowed;
/** Creates a {@link Builder} for a {@link SafetySource}. */
public Builder(@SafetySourceType int type) {
mType = type;
}
/** Sets the id of this safety source. */
@NonNull
public Builder setId(@Nullable String id) {
mId = id;
return this;
}
/** Sets the package name of this safety source. */
@NonNull
public Builder setPackageName(@Nullable String packageName) {
mPackageName = packageName;
return this;
}
/** Sets the resource id of the title of this safety source. */
@NonNull
public Builder setTitleResId(@StringRes int titleResId) {
mTitleResId = titleResId;
return this;
}
/** Sets the resource id of the title for work of this safety source. */
@NonNull
public Builder setTitleForWorkResId(@StringRes int titleForWorkResId) {
mTitleForWorkResId = titleForWorkResId;
return this;
}
/** Sets the resource id of the summary of this safety source. */
@NonNull
public Builder setSummaryResId(@StringRes int summaryResId) {
mSummaryResId = summaryResId;
return this;
}
/** Sets the intent action of this safety source. */
@NonNull
public Builder setIntentAction(@Nullable String intentAction) {
mIntentAction = intentAction;
return this;
}
/** Sets the profile property of this safety source. */
@NonNull
public Builder setProfile(@Profile int profile) {
mProfile = profile;
return this;
}
/** Sets the initial display state of this safety source. */
@NonNull
public Builder setInitialDisplayState(@InitialDisplayState int initialDisplayState) {
mInitialDisplayState = initialDisplayState;
return this;
}
/** Sets the maximum severity level of this safety source. */
@NonNull
public Builder setMaxSeverityLevel(int maxSeverityLevel) {
mMaxSeverityLevel = maxSeverityLevel;
return this;
}
/** Sets the resource id of the search terms of this safety source. */
@NonNull
public Builder setSearchTermsResId(@StringRes int searchTermsResId) {
mSearchTermsResId = searchTermsResId;
return this;
}
/** Sets the broadcast receiver class name of this safety source. */
@NonNull
public Builder setBroadcastReceiverClassName(@Nullable String broadcastReceiverClassName) {
mBroadcastReceiverClassName = broadcastReceiverClassName;
return this;
}
/** Sets the logging allowed property of this safety source. */
@NonNull
public Builder setLoggingAllowed(boolean loggingAllowed) {
mLoggingAllowed = loggingAllowed;
return this;
}
/** Sets the refresh on page open allowed property of this safety source. */
@NonNull
public Builder setRefreshOnPageOpenAllowed(boolean refreshOnPageOpenAllowed) {
mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed;
return this;
}
/** Creates the {@link SafetySource} defined by this {@link Builder}. */
@NonNull
public SafetySource build() {
if (mType != SAFETY_SOURCE_TYPE_STATIC
&& mType != SAFETY_SOURCE_TYPE_DYNAMIC
&& mType != SAFETY_SOURCE_TYPE_ISSUE_ONLY) {
throw new IllegalStateException("Unexpected type");
}
boolean isStatic = mType == SAFETY_SOURCE_TYPE_STATIC;
boolean isDynamic = mType == SAFETY_SOURCE_TYPE_DYNAMIC;
boolean isIssueOnly = mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY;
BuilderUtils.validateAttribute(mId, "id", true, false);
BuilderUtils.validateAttribute(mPackageName, "packageName", isDynamic || isIssueOnly,
isStatic);
int initialDisplayState = BuilderUtils.validateIntDef(mInitialDisplayState,
"initialDisplayState", false, isStatic || isIssueOnly,
INITIAL_DISPLAY_STATE_ENABLED, INITIAL_DISPLAY_STATE_ENABLED,
INITIAL_DISPLAY_STATE_DISABLED, INITIAL_DISPLAY_STATE_HIDDEN);
boolean isEnabled = initialDisplayState == INITIAL_DISPLAY_STATE_ENABLED;
boolean isHidden = initialDisplayState == INITIAL_DISPLAY_STATE_HIDDEN;
int titleResId = BuilderUtils.validateResId(mTitleResId, "title",
(isDynamic && !isHidden) || isStatic, isIssueOnly || isHidden);
int summaryResId = BuilderUtils.validateResId(mSummaryResId, "summary",
(isDynamic && !isHidden) || isStatic, isIssueOnly || isHidden);
BuilderUtils.validateAttribute(mIntentAction, "intentAction",
(isDynamic && isEnabled) || isStatic, isIssueOnly || isHidden);
int profile = BuilderUtils.validateIntDef(mProfile, "profile", true, false,
PROFILE_NONE, PROFILE_PRIMARY, PROFILE_ALL);
int titleForWorkResId = BuilderUtils.validateResId(mTitleForWorkResId, "titleForWork",
((isDynamic && !isHidden) || isStatic) && profile == PROFILE_ALL,
isIssueOnly || isHidden || profile == PROFILE_PRIMARY);
int maxSeverityLevel = BuilderUtils.validateInteger(mMaxSeverityLevel,
"maxSeverityLevel", false, isStatic, Integer.MAX_VALUE);
int searchTermsResId = BuilderUtils.validateResId(mSearchTermsResId, "searchTerms",
false, isIssueOnly);
BuilderUtils.validateAttribute(mBroadcastReceiverClassName,
"broadcastReceiverClassName", false, isStatic);
boolean loggingAllowed = BuilderUtils.validateBoolean(mLoggingAllowed, "loggingAllowed",
false, isStatic, true);
boolean refreshOnPageOpenAllowed = BuilderUtils.validateBoolean(
mRefreshOnPageOpenAllowed, "refreshOnPageOpenAllowed", false, isStatic, false);
return new SafetySource(mType, mId, mPackageName, titleResId, titleForWorkResId,
summaryResId, mIntentAction, profile, initialDisplayState, maxSeverityLevel,
searchTermsResId, mBroadcastReceiverClassName, loggingAllowed,
refreshOnPageOpenAllowed);
}
}
}