/*
* 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.health.connect;
import static android.health.connect.datatypes.MedicalDataSource.validateMedicalDataSourceIds;
import static com.android.healthfitness.flags.Flags.FLAG_PERSONAL_HEALTH_RECORD;
import static java.util.Objects.hash;
import static java.util.Objects.requireNonNull;
import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.health.connect.datatypes.FhirVersion;
import android.health.connect.datatypes.MedicalDataSource;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.healthfitness.flags.Flags;
import java.util.Set;
/**
* An upsert request for {@link HealthConnectManager#upsertMedicalResources}.
*
*
Medical data is represented using the Fast Healthcare
* Interoperability Resources (FHIR) standard.
*/
@FlaggedApi(FLAG_PERSONAL_HEALTH_RECORD)
public final class UpsertMedicalResourceRequest implements Parcelable {
@NonNull private final String mDataSourceId;
@NonNull private final FhirVersion mFhirVersion;
@NonNull private final String mData;
private int mDataSize;
@NonNull
public static final Creator CREATOR =
new Creator<>() {
@Override
public UpsertMedicalResourceRequest createFromParcel(Parcel in) {
return new UpsertMedicalResourceRequest(in);
}
@Override
public UpsertMedicalResourceRequest[] newArray(int size) {
return new UpsertMedicalResourceRequest[size];
}
};
/**
* Creates a new instance of {@link UpsertMedicalResourceRequest}. Please see {@link
* UpsertMedicalResourceRequest.Builder} for more detailed parameters information.
*/
private UpsertMedicalResourceRequest(
@NonNull String dataSourceId, @NonNull FhirVersion fhirVersion, @NonNull String data) {
requireNonNull(dataSourceId);
requireNonNull(fhirVersion);
requireNonNull(data);
validateMedicalDataSourceIds(Set.of(dataSourceId));
mDataSourceId = dataSourceId;
mFhirVersion = fhirVersion;
mData = data;
}
private UpsertMedicalResourceRequest(@NonNull Parcel in) {
requireNonNull(in);
int dataAvailStartPosition = in.dataAvail();
mDataSourceId = requireNonNull(in.readString());
validateMedicalDataSourceIds(Set.of(mDataSourceId));
mFhirVersion =
requireNonNull(
in.readParcelable(FhirVersion.class.getClassLoader(), FhirVersion.class));
mData = requireNonNull(in.readString());
if (Flags.phrUpsertFixParcelSizeCalculation()) {
mDataSize = dataAvailStartPosition - in.dataAvail();
} else {
mDataSize = in.dataSize();
}
}
/**
* Returns the unique ID of the existing {@link MedicalDataSource}, to represent where the
* {@code data} is coming from.
*/
@NonNull
public String getDataSourceId() {
return mDataSourceId;
}
/**
* Returns the FHIR version being used for {@code data}. For the request to succeed this must
* match the {@link MedicalDataSource#getFhirVersion()} FHIR version of the {@link
* MedicalDataSource} with the provided {@code dataSourceId}.
*/
@NonNull
public FhirVersion getFhirVersion() {
return mFhirVersion;
}
/** Returns the FHIR resource data in JSON representation. */
@NonNull
public String getData() {
return mData;
}
/**
* Returns the size of the parcel when the class was created from Parcel.
*
* @hide
*/
public long getDataSize() {
return mDataSize;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
requireNonNull(dest);
dest.writeString(mDataSourceId);
dest.writeParcelable(mFhirVersion, 0);
dest.writeString(mData);
}
@Override
public int hashCode() {
return hash(getDataSourceId(), getFhirVersion(), getData());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof UpsertMedicalResourceRequest that)) return false;
return getDataSourceId().equals(that.getDataSourceId())
&& getFhirVersion().equals(that.getFhirVersion())
&& getData().equals(that.getData());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName()).append("{");
sb.append("dataSourceId=").append(mDataSourceId);
sb.append(",fhirVersion=").append(mFhirVersion);
sb.append(",data=").append(mData);
sb.append("}");
return sb.toString();
}
/** Builder class for {@link UpsertMedicalResourceRequest}. */
public static final class Builder {
private String mDataSourceId;
private FhirVersion mFhirVersion;
private String mData;
/**
* Constructs a new {@link UpsertMedicalResourceRequest.Builder} instance.
*
* @param dataSourceId The unique identifier of the existing {@link MedicalDataSource},
* representing where the data comes from.
* @param fhirVersion The {@link FhirVersion} object that represents the FHIR version being
* used for {@code data}. This has to match the FHIR version of the {@link
* MedicalDataSource}.
* @param data The FHIR resource data in JSON representation.
* @throws IllegalArgumentException if the provided {@code dataSourceId} is not a valid ID.
*/
public Builder(
@NonNull String dataSourceId,
@NonNull FhirVersion fhirVersion,
@NonNull String data) {
requireNonNull(dataSourceId);
requireNonNull(fhirVersion);
requireNonNull(data);
validateMedicalDataSourceIds(Set.of(dataSourceId));
mDataSourceId = dataSourceId;
mFhirVersion = fhirVersion;
mData = data;
}
/** Constructs a clone of the other {@link UpsertMedicalResourceRequest.Builder}. */
public Builder(@NonNull Builder other) {
requireNonNull(other);
mDataSourceId = other.mDataSourceId;
mFhirVersion = other.mFhirVersion;
mData = other.mData;
}
/** Constructs a clone of the other {@link UpsertMedicalResourceRequest} instance. */
public Builder(@NonNull UpsertMedicalResourceRequest other) {
requireNonNull(other);
mDataSourceId = other.getDataSourceId();
mFhirVersion = other.getFhirVersion();
mData = other.getData();
}
/**
* Sets the unique ID of the existing {@link MedicalDataSource}, to represent where the
* {@code data} is coming from.
*
* @throws IllegalArgumentException if the provided {@code dataSourceId} is not a valid ID.
*/
@NonNull
public Builder setDataSourceId(@NonNull String dataSourceId) {
requireNonNull(dataSourceId);
validateMedicalDataSourceIds(Set.of(dataSourceId));
mDataSourceId = dataSourceId;
return this;
}
/**
* Sets the FHIR version being used for {@code data}. For the request to succeed this must
* match the {@link MedicalDataSource#getFhirVersion()} FHIR version} of the {@link
* MedicalDataSource} with the provided {@code dataSourceId}.
*/
@NonNull
public Builder setFhirVersion(@NonNull FhirVersion fhirVersion) {
requireNonNull(fhirVersion);
mFhirVersion = fhirVersion;
return this;
}
/** Sets the FHIR resource data in JSON format. */
@NonNull
public Builder setData(@NonNull String data) {
requireNonNull(data);
mData = data;
return this;
}
/**
* Returns a new instance of {@link UpsertMedicalResourceRequest} with the specified
* parameters.
*/
@NonNull
public UpsertMedicalResourceRequest build() {
return new UpsertMedicalResourceRequest(mDataSourceId, mFhirVersion, mData);
}
}
}