/* * Copyright (C) 2024 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.app.wearable; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; import java.time.Duration; /** * Data class for a data request for wearable sensing. * * @hide */ @FlaggedApi(Flags.FLAG_ENABLE_DATA_REQUEST_OBSERVER_API) @SystemApi public final class WearableSensingDataRequest implements Parcelable { private static final int MAX_REQUEST_SIZE = 200; private static final Duration RATE_LIMIT_WINDOW_SIZE = Duration.ofMinutes(1); private static final int RATE_LIMIT = 30; private final int mDataType; @NonNull private final PersistableBundle mRequestDetails; private WearableSensingDataRequest(int dataType, @NonNull PersistableBundle requestDetails) { mDataType = dataType; mRequestDetails = requestDetails; } /** Returns the data type this request is for. */ public int getDataType() { return mDataType; } /** Returns the details for this request. */ @NonNull public PersistableBundle getRequestDetails() { return mRequestDetails; } /** Returns the data size of this object when it is parcelled. */ public int getDataSize() { Parcel parcel = Parcel.obtain(); try { writeToParcel(parcel, describeContents()); return parcel.dataSize(); } finally { parcel.recycle(); } } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mDataType); dest.writeTypedObject(mRequestDetails, flags); } @Override public int describeContents() { return 0; } @Override public String toString() { return "WearableSensingDataRequest { " + "dataType = " + mDataType + ", " + "requestDetails = " + mRequestDetails + " }"; } /** * Returns a String representation of this data request that shows its contents. * * @hide */ public String toExpandedString() { if (mRequestDetails != null) { // Trigger unparcelling so that its individual fields will be listed in toString boolean unused = mRequestDetails.getBoolean( "PlaceholderForWearableSensingDataRequest#toExpandedString()"); } return toString(); } /** * The bundle key for this class of object, used in {@code RemoteCallback#sendResult}. * * @hide */ public static final String REQUEST_BUNDLE_KEY = "android.app.wearable.WearableSensingDataRequestBundleKey"; /** * The bundle key for the status callback for a data request, used in {@code * RemoteCallback#sendResult}. * * @hide */ public static final String REQUEST_STATUS_CALLBACK_BUNDLE_KEY = "android.app.wearable.WearableSensingDataRequestStatusCallbackBundleKey"; public static final @NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public WearableSensingDataRequest[] newArray(int size) { return new WearableSensingDataRequest[size]; } @Override public WearableSensingDataRequest createFromParcel(@NonNull Parcel in) { int dataType = in.readInt(); PersistableBundle requestDetails = in.readTypedObject(PersistableBundle.CREATOR); return new WearableSensingDataRequest(dataType, requestDetails); } }; /** * Returns the maximum allowed size of a WearableSensingDataRequest when it is parcelled. * Instances that exceed this size can be constructed, but will be rejected by the system when * they leave the isolated WearableSensingService. */ public static int getMaxRequestSize() { return MAX_REQUEST_SIZE; } /** * Returns the rolling time window used to perform rate limiting on data requests leaving the * WearableSensingService. */ @NonNull public static Duration getRateLimitWindowSize() { return RATE_LIMIT_WINDOW_SIZE; } /** * Returns the number of data requests allowed to leave the WearableSensingService in each * {@link #getRateLimitWindowSize()}. */ public static int getRateLimit() { return RATE_LIMIT; } /** A builder for WearableSensingDataRequest. */ @FlaggedApi(Flags.FLAG_ENABLE_DATA_REQUEST_OBSERVER_API) public static final class Builder { private int mDataType; private PersistableBundle mRequestDetails; public Builder(int dataType) { mDataType = dataType; } /** Sets the request details. */ public @NonNull Builder setRequestDetails(@NonNull PersistableBundle requestDetails) { mRequestDetails = requestDetails; return this; } /** Builds the WearableSensingDataRequest. */ public @NonNull WearableSensingDataRequest build() { if (mRequestDetails == null) { mRequestDetails = PersistableBundle.EMPTY; } return new WearableSensingDataRequest(mDataType, mRequestDetails); } } }