blob: 265e3e7c8a014cdc3176925959163afecf5bfa65 [file] [log] [blame]
/*
* Copyright (C) 2017 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.telephony;
import android.annotation.BytesLong;
import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
import android.util.RecurrenceRule;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Period;
import java.time.ZonedDateTime;
import java.util.Iterator;
/**
* Description of a billing relationship plan between a carrier and a specific
* subscriber. This information is used to present more useful UI to users, such
* as explaining how much mobile data they have remaining, and what will happen
* when they run out.
*
* @see SubscriptionManager#setSubscriptionPlans(int, java.util.List)
* @see SubscriptionManager#getSubscriptionPlans(int)
* @hide
*/
@SystemApi
public final class SubscriptionPlan implements Parcelable {
/** {@hide} */
@IntDef(prefix = "LIMIT_BEHAVIOR_", value = {
LIMIT_BEHAVIOR_UNKNOWN,
LIMIT_BEHAVIOR_DISABLED,
LIMIT_BEHAVIOR_BILLED,
LIMIT_BEHAVIOR_THROTTLED,
})
@Retention(RetentionPolicy.SOURCE)
public @interface LimitBehavior {}
/** When a resource limit is hit, the behavior is unknown. */
public static final int LIMIT_BEHAVIOR_UNKNOWN = -1;
/** When a resource limit is hit, access is disabled. */
public static final int LIMIT_BEHAVIOR_DISABLED = 0;
/** When a resource limit is hit, the user is billed automatically. */
public static final int LIMIT_BEHAVIOR_BILLED = 1;
/** When a resource limit is hit, access is throttled to a slower rate. */
public static final int LIMIT_BEHAVIOR_THROTTLED = 2;
/** Value indicating a number of bytes is unknown. */
public static final long BYTES_UNKNOWN = -1;
/** Value indicating a number of bytes is unlimited. */
public static final long BYTES_UNLIMITED = Long.MAX_VALUE;
/** Value indicating a timestamp is unknown. */
public static final long TIME_UNKNOWN = -1;
private final RecurrenceRule cycleRule;
private CharSequence title;
private CharSequence summary;
private long dataLimitBytes = BYTES_UNKNOWN;
private int dataLimitBehavior = LIMIT_BEHAVIOR_UNKNOWN;
private long dataUsageBytes = BYTES_UNKNOWN;
private long dataUsageTime = TIME_UNKNOWN;
private SubscriptionPlan(RecurrenceRule cycleRule) {
this.cycleRule = Preconditions.checkNotNull(cycleRule);
}
private SubscriptionPlan(Parcel source) {
cycleRule = source.readParcelable(null);
title = source.readCharSequence();
summary = source.readCharSequence();
dataLimitBytes = source.readLong();
dataLimitBehavior = source.readInt();
dataUsageBytes = source.readLong();
dataUsageTime = source.readLong();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(cycleRule, flags);
dest.writeCharSequence(title);
dest.writeCharSequence(summary);
dest.writeLong(dataLimitBytes);
dest.writeInt(dataLimitBehavior);
dest.writeLong(dataUsageBytes);
dest.writeLong(dataUsageTime);
}
@Override
public String toString() {
return new StringBuilder("SubscriptionPlan{")
.append("cycleRule=").append(cycleRule)
.append(" title=").append(title)
.append(" summary=").append(summary)
.append(" dataLimitBytes=").append(dataLimitBytes)
.append(" dataLimitBehavior=").append(dataLimitBehavior)
.append(" dataUsageBytes=").append(dataUsageBytes)
.append(" dataUsageTime=").append(dataUsageTime)
.append("}").toString();
}
public static final Parcelable.Creator<SubscriptionPlan> CREATOR = new Parcelable.Creator<SubscriptionPlan>() {
@Override
public SubscriptionPlan createFromParcel(Parcel source) {
return new SubscriptionPlan(source);
}
@Override
public SubscriptionPlan[] newArray(int size) {
return new SubscriptionPlan[size];
}
};
/** {@hide} */
public @NonNull RecurrenceRule getCycleRule() {
return cycleRule;
}
/** Return the short title of this plan. */
public @Nullable CharSequence getTitle() {
return title;
}
/** Return the short summary of this plan. */
public @Nullable CharSequence getSummary() {
return summary;
}
/**
* Return the usage threshold at which data access changes according to
* {@link #getDataLimitBehavior()}.
*/
public @BytesLong long getDataLimitBytes() {
return dataLimitBytes;
}
/**
* Return the behavior of data access when usage reaches
* {@link #getDataLimitBytes()}.
*/
public @LimitBehavior int getDataLimitBehavior() {
return dataLimitBehavior;
}
/**
* Return a snapshot of currently known mobile data usage at
* {@link #getDataUsageTime()}.
*/
public @BytesLong long getDataUsageBytes() {
return dataUsageBytes;
}
/**
* Return the time at which {@link #getDataUsageBytes()} was valid.
*/
public @CurrentTimeMillisLong long getDataUsageTime() {
return dataUsageTime;
}
/**
* Return an iterator that will return all valid data usage cycles based on
* any recurrence rules. The iterator starts from the currently active cycle
* and walks backwards through time.
*/
public Iterator<Pair<ZonedDateTime, ZonedDateTime>> cycleIterator() {
return cycleRule.cycleIterator();
}
/**
* Builder for a {@link SubscriptionPlan}.
*/
public static class Builder {
private final SubscriptionPlan plan;
/** {@hide} */
public Builder(ZonedDateTime start, ZonedDateTime end, Period period) {
plan = new SubscriptionPlan(new RecurrenceRule(start, end, period));
}
/**
* Start defining a {@link SubscriptionPlan} that covers a very specific
* window of time, and never automatically recurs.
*/
public static Builder createNonrecurring(ZonedDateTime start, ZonedDateTime end) {
if (!end.isAfter(start)) {
throw new IllegalArgumentException(
"End " + end + " isn't after start " + start);
}
return new Builder(start, end, null);
}
/**
* Start defining a {@link SubscriptionPlan} that will recur
* automatically every month. It will always recur on the same day of a
* particular month. When a particular month ends before the defined
* recurrence day, the plan will recur on the last instant of that
* month.
*/
public static Builder createRecurringMonthly(ZonedDateTime start) {
return new Builder(start, null, Period.ofMonths(1));
}
/**
* Start defining a {@link SubscriptionPlan} that will recur
* automatically every week.
*/
public static Builder createRecurringWeekly(ZonedDateTime start) {
return new Builder(start, null, Period.ofDays(7));
}
/**
* Start defining a {@link SubscriptionPlan} that will recur
* automatically every day.
*/
public static Builder createRecurringDaily(ZonedDateTime start) {
return new Builder(start, null, Period.ofDays(1));
}
public SubscriptionPlan build() {
return plan;
}
/** Set the short title of this plan. */
public Builder setTitle(@Nullable CharSequence title) {
plan.title = title;
return this;
}
/** Set the short summary of this plan. */
public Builder setSummary(@Nullable CharSequence summary) {
plan.summary = summary;
return this;
}
/**
* Set the usage threshold at which data access changes.
*
* @param dataLimitBytes the usage threshold at which data access
* changes
* @param dataLimitBehavior the behavior of data access when usage
* reaches the threshold
*/
public Builder setDataLimit(@BytesLong long dataLimitBytes,
@LimitBehavior int dataLimitBehavior) {
if (dataLimitBytes < 0) {
throw new IllegalArgumentException("Limit bytes must be positive");
}
if (dataLimitBehavior < 0) {
throw new IllegalArgumentException("Limit behavior must be defined");
}
plan.dataLimitBytes = dataLimitBytes;
plan.dataLimitBehavior = dataLimitBehavior;
return this;
}
/**
* Set a snapshot of currently known mobile data usage.
*
* @param dataUsageBytes the currently known mobile data usage
* @param dataUsageTime the time at which this snapshot was valid
*/
public Builder setDataUsage(@BytesLong long dataUsageBytes,
@CurrentTimeMillisLong long dataUsageTime) {
if (dataUsageBytes < 0) {
throw new IllegalArgumentException("Usage bytes must be positive");
}
if (dataUsageTime < 0) {
throw new IllegalArgumentException("Usage time must be positive");
}
plan.dataUsageBytes = dataUsageBytes;
plan.dataUsageTime = dataUsageTime;
return this;
}
}
}