blob: 9868064ff079158b98ab08369458209cdea7eb91 [file] [log] [blame]
/*
* Copyright (C) 2021 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;
import static android.os.Build.VERSION_CODES.TIRAMISU;
import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.RequiresApi;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
* Data for a safety source status in the Safety Center page, which conveys the overall state of
* the safety source and allows a user to navigate to the source.
*
* @hide
*/
@SystemApi
@RequiresApi(TIRAMISU)
public final class SafetySourceStatus implements Parcelable {
/**
* Indicates that no status is currently associated with the information. This may be due to the
* source not having sufficient information or opinion on the status level.
*
* <p>This status will be reflected in the UI through a grey icon.
*/
public static final int STATUS_LEVEL_NONE = 100;
/**
* Indicates that no issues were detected.
*
* <p>This status will be reflected in the UI through a green icon.
*/
public static final int STATUS_LEVEL_OK = 200;
/**
* Indicates the presence of a medium-level issue which the user is encouraged to act on.
*
* <p>This status will be reflected in the UI through a yellow icon.
*/
public static final int STATUS_LEVEL_RECOMMENDATION = 300;
/**
* Indicates the presence of a critical or urgent safety issue that should be addressed by the
* user.
*
* <p>This status will be reflected in the UI through a red icon.
*/
public static final int STATUS_LEVEL_CRITICAL_WARNING = 400;
@NonNull
public static final Parcelable.Creator<SafetySourceStatus> CREATOR =
new Parcelable.Creator<SafetySourceStatus>() {
@Override
public SafetySourceStatus createFromParcel(Parcel in) {
return new Builder(
TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in),
TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in),
in.readInt(),
PendingIntent.readPendingIntentOrNullFromParcel(in))
.setIconAction(in.readTypedObject(IconAction.CREATOR))
.setEnabled(in.readBoolean())
.build();
}
@Override
public SafetySourceStatus[] newArray(int size) {
return new SafetySourceStatus[size];
}
};
@NonNull
private final CharSequence mTitle;
@NonNull
private final CharSequence mSummary;
@StatusLevel
private final int mStatusLevel;
@NonNull
private final PendingIntent mPendingIntent;
@Nullable
private final IconAction mIconAction;
private final boolean mEnabled;
private SafetySourceStatus(@NonNull CharSequence title, @NonNull CharSequence summary,
@StatusLevel int statusLevel, @NonNull PendingIntent pendingIntent,
@Nullable IconAction iconAction, boolean enabled) {
this.mTitle = title;
this.mSummary = summary;
this.mStatusLevel = statusLevel;
this.mPendingIntent = pendingIntent;
this.mIconAction = iconAction;
this.mEnabled = enabled;
}
/** Returns the localized title of the safety source status to be displayed in the UI. */
@NonNull
public CharSequence getTitle() {
return mTitle;
}
/** Returns the localized summary of the safety source status to be displayed in the UI. */
@NonNull
public CharSequence getSummary() {
return mSummary;
}
/** Returns the {@link StatusLevel} of the status. */
@StatusLevel
public int getStatusLevel() {
return mStatusLevel;
}
/**
* Returns the {@link PendingIntent} that will be invoked when the safety source status UI is
* clicked on.
*/
@NonNull
public PendingIntent getPendingIntent() {
return mPendingIntent;
}
/**
* Returns an optional {@link IconAction} to be displayed in the safety source status UI.
*
* <p>The icon action will be a clickable icon which performs an action as indicated by the
* icon.
*/
@Nullable
public IconAction getIconAction() {
return mIconAction;
}
/**
* Returns whether the safety source status is enabled.
*
* <p>A safety source status should be disabled if it is currently unavailable on the device.
*
* <p>If disabled, the status will show as grayed out in the UI, and interactions with it may
* be limited.
*/
public boolean isEnabled() {
return mEnabled;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
TextUtils.writeToParcel(mTitle, dest, flags);
TextUtils.writeToParcel(mSummary, dest, flags);
dest.writeInt(mStatusLevel);
mPendingIntent.writeToParcel(dest, flags);
dest.writeTypedObject(mIconAction, flags);
dest.writeBoolean(mEnabled);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SafetySourceStatus)) return false;
SafetySourceStatus that = (SafetySourceStatus) o;
return mStatusLevel == that.mStatusLevel
&& mEnabled == that.mEnabled
&& TextUtils.equals(mTitle, that.mTitle)
&& TextUtils.equals(mSummary, that.mSummary)
&& mPendingIntent.equals(that.mPendingIntent)
&& Objects.equals(mIconAction, that.mIconAction);
}
@Override
public int hashCode() {
return Objects.hash(mTitle, mSummary, mStatusLevel, mPendingIntent, mIconAction,
mEnabled);
}
@Override
public String toString() {
return "SafetySourceStatus{"
+ "mTitle="
+ mTitle
+ ", mSummary="
+ mSummary
+ ", mStatusLevel="
+ mStatusLevel
+ ", mPendingIntent="
+ mPendingIntent
+ ", mIconAction="
+ mIconAction
+ ", mEnabled="
+ mEnabled
+ '}';
}
/**
* Data for an action supported from a safety source status {@link SafetySourceStatus} in the
* Safety Center page.
*
* <p>The purpose of the action is to add a surface to allow the user to perform an action
* relating to the safety source status.
*
* <p>The action will be shown as a clickable icon chosen from a predefined set of icons (see
* {@link IconType}). The icon should indicate to the user what action will be performed on
* clicking on it.
*
* @hide
*/
@SystemApi
public static final class IconAction implements Parcelable {
@NonNull
public static final Parcelable.Creator<IconAction> CREATOR =
new Parcelable.Creator<IconAction>() {
@Override
public IconAction createFromParcel(Parcel in) {
int iconType = in.readInt();
PendingIntent pendingIntent =
requireNonNull(PendingIntent.readPendingIntentOrNullFromParcel(in));
return new IconAction(iconType, pendingIntent);
}
@Override
public IconAction[] newArray(int size) {
return new IconAction[size];
}
};
@IconType
private final int mIconType;
@NonNull
private final PendingIntent mPendingIntent;
public IconAction(@IconType int iconType, @NonNull PendingIntent pendingIntent) {
this.mIconType = iconType;
this.mPendingIntent = pendingIntent;
}
/**
* Returns the type of icon to be displayed in the UI.
*
* <p>The icon type should indicate what action will be performed if when invoked.
*/
@IconType
public int getIconType() {
return mIconType;
}
/** Returns a {@link PendingIntent} to be invoked when the icon action is clicked on. */
@NonNull
public PendingIntent getPendingIntent() {
return mPendingIntent;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mIconType);
mPendingIntent.writeToParcel(dest, flags);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof IconAction)) return false;
IconAction that = (IconAction) o;
return mIconType == that.mIconType && mPendingIntent.equals(that.mPendingIntent);
}
@Override
public int hashCode() {
return Objects.hash(mIconType, mPendingIntent);
}
@Override
public String toString() {
return "IconAction{"
+ "mIconType="
+ mIconType
+ ", mPendingIntent="
+ mPendingIntent
+ '}';
}
/** Indicates a gear (cog) icon. */
public static final int ICON_TYPE_GEAR = 100;
/** Indicates an information icon. */
public static final int ICON_TYPE_INFO = 200;
/**
* All possible icons which can be displayed in an {@link IconAction}.
*
* @hide
*/
@IntDef(prefix = {"ICON_TYPE_"}, value = {
ICON_TYPE_GEAR,
ICON_TYPE_INFO,
})
@Retention(RetentionPolicy.SOURCE)
public @interface IconType {
}
}
/**
* All possible status levels for the safety source status.
*
* <p>The status level is meant to convey the overall state of the safety source and contributes
* to the top-level safety status of the user. Choose the status level to represent the most
* severe of all the safety source's issues.
*
* <p>The numerical values of the levels are not used directly, rather they are used to build
* a continuum of levels which support relative comparison.
*
* <p>The higher the status level, the worse the safety level of the source and the higher
* the threat to the user.
*
* @hide
*/
@IntDef(prefix = {"STATUS_LEVEL_"}, value = {
STATUS_LEVEL_NONE,
STATUS_LEVEL_OK,
STATUS_LEVEL_RECOMMENDATION,
STATUS_LEVEL_CRITICAL_WARNING
})
@Retention(RetentionPolicy.SOURCE)
public @interface StatusLevel {
}
/** Builder class for {@link SafetySourceStatus}. */
public static final class Builder {
@NonNull
private final CharSequence mTitle;
@NonNull
private final CharSequence mSummary;
@StatusLevel
private final int mStatusLevel;
@NonNull
private final PendingIntent mPendingIntent;
@Nullable
private IconAction mIconAction;
private boolean mEnabled = true;
/** Creates a {@link Builder} for a {@link SafetySourceStatus}. */
public Builder(@NonNull CharSequence title, @NonNull CharSequence summary,
@StatusLevel int statusLevel, @NonNull PendingIntent pendingIntent) {
this.mTitle = requireNonNull(title);
this.mSummary = requireNonNull(summary);
this.mStatusLevel = statusLevel;
this.mPendingIntent = requireNonNull(pendingIntent);
}
/**
* Sets an optional {@link IconAction} for the safety source status.
*
* @see #getIconAction()
*/
@NonNull
public Builder setIconAction(@Nullable IconAction iconAction) {
this.mIconAction = iconAction;
return this;
}
/**
* Sets whether the safety source status is enabled.
*
* <p>By default, the safety source status will be enabled.
*
* @see #isEnabled()
*/
@NonNull
public Builder setEnabled(boolean enabled) {
this.mEnabled = enabled;
return this;
}
/** Creates the {@link SafetySourceStatus} defined by this {@link Builder}. */
@NonNull
public SafetySourceStatus build() {
return new SafetySourceStatus(mTitle, mSummary, mStatusLevel, mPendingIntent,
mIconAction, mEnabled);
}
}
}