• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.health.connect.datatypes;
18 
19 import static com.android.healthfitness.flags.Flags.FLAG_PERSONAL_HEALTH_RECORD;
20 
21 import static java.util.Objects.hash;
22 import static java.util.Objects.requireNonNull;
23 
24 import android.annotation.FlaggedApi;
25 import android.annotation.NonNull;
26 import android.os.Parcel;
27 import android.os.Parcelable;
28 
29 import java.util.Set;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32 
33 /**
34  * Represents the FHIR version. This is designed according to <a
35  * href="https://build.fhir.org/versions.html#versions">the official FHIR versions</a> of the Fast
36  * Healthcare Interoperability Resources (FHIR) standard. "label", which represents a 'working'
37  * version, is not supported for now.
38  *
39  * <p>The versions R4 (4.0.1) and R4B (4.3.0) are supported in Health Connect.
40  */
41 @FlaggedApi(FLAG_PERSONAL_HEALTH_RECORD)
42 public final class FhirVersion implements Parcelable {
43     private static final FhirVersion R4_FHIR_VERSION = FhirVersion.parseFhirVersion("4.0.1");
44     private static final FhirVersion R4B_FHIR_VERSION = FhirVersion.parseFhirVersion("4.3.0");
45     private static final Set<FhirVersion> SUPPORTED_FHIR_VERSIONS =
46             Set.of(R4_FHIR_VERSION, R4B_FHIR_VERSION);
47 
48     private final int mMajor;
49     private final int mMinor;
50     private final int mPatch;
51 
52     private static final String VERSION_REGEX = "(\\d+)\\.(\\d+)\\.(\\d+)";
53 
FhirVersion(int major, int minor, int patch)54     private FhirVersion(int major, int minor, int patch) {
55         mMajor = major;
56         mMinor = minor;
57         mPatch = patch;
58         validateVersionNumbersNotNegative();
59     }
60 
61     /**
62      * Constructs this object with the data present in {@code parcel}. It should be in the same
63      * order as {@link FhirVersion#writeToParcel}.
64      */
FhirVersion(@onNull Parcel in)65     private FhirVersion(@NonNull Parcel in) {
66         requireNonNull(in);
67         mMajor = in.readInt();
68         mMinor = in.readInt();
69         mPatch = in.readInt();
70         validateVersionNumbersNotNegative();
71     }
72 
73     @NonNull
74     public static final Creator<FhirVersion> CREATOR =
75             new Creator<>() {
76                 @Override
77                 public FhirVersion createFromParcel(Parcel in) {
78                     return new FhirVersion(in);
79                 }
80 
81                 @Override
82                 public FhirVersion[] newArray(int size) {
83                     return new FhirVersion[size];
84                 }
85             };
86 
87     /**
88      * Creates a {@link FhirVersion} object with the version of string format.
89      *
90      * <p>The format should look like "4.0.1" which contains 3 numbers - major, minor and patch,
91      * separated by ".". This aligns with <a
92      * href="https://build.fhir.org/versions.html#versions">the official FHIR versions</a>. Note
93      * that the "label" is not supported for now, which represents a 'working' version.
94      */
95     @NonNull
parseFhirVersion(@onNull String fhirVersionString)96     public static FhirVersion parseFhirVersion(@NonNull String fhirVersionString) {
97         requireNonNull(fhirVersionString);
98         Pattern pattern = Pattern.compile(VERSION_REGEX);
99         Matcher matcher = pattern.matcher(fhirVersionString);
100         if (!matcher.matches()) {
101             throw new IllegalArgumentException("Invalid FHIR version string: " + fhirVersionString);
102         }
103         return new FhirVersion(
104                 Integer.parseInt(matcher.group(1)),
105                 Integer.parseInt(matcher.group(2)),
106                 Integer.parseInt(matcher.group(3)));
107     }
108 
109     /** Returns the major version. */
getMajor()110     public int getMajor() {
111         return mMajor;
112     }
113 
114     /** Returns the minor version. */
getMinor()115     public int getMinor() {
116         return mMinor;
117     }
118 
119     /** Returns the patch version. */
getPatch()120     public int getPatch() {
121         return mPatch;
122     }
123 
124     @Override
describeContents()125     public int describeContents() {
126         return 0;
127     }
128 
129     /** Populates a {@link Parcel} with the self information. */
130     @Override
writeToParcel(@onNull Parcel dest, int flags)131     public void writeToParcel(@NonNull Parcel dest, int flags) {
132         requireNonNull(dest);
133         dest.writeInt(getMajor());
134         dest.writeInt(getMinor());
135         dest.writeInt(getPatch());
136     }
137 
138     /** Indicates whether some other object is "equal to" this one. */
139     @Override
equals(Object o)140     public boolean equals(Object o) {
141         if (this == o) return true;
142         if (!(o instanceof FhirVersion that)) return false;
143         return getMajor() == that.getMajor()
144                 && getMinor() == that.getMinor()
145                 && getPatch() == that.getPatch();
146     }
147 
148     /** Returns a hash code value for the object. */
149     @Override
hashCode()150     public int hashCode() {
151         return hash(getMajor(), getMinor(), getPatch());
152     }
153 
154     /** Returns the string representation of the FHIR version. */
toString()155     public String toString() {
156         return String.format("%d.%d.%d", mMajor, mMinor, mPatch);
157     }
158 
159     /** Returns {@code true} if the {@link FhirVersion} is supported by Health Connect. */
isSupportedFhirVersion()160     public boolean isSupportedFhirVersion() {
161         return SUPPORTED_FHIR_VERSIONS.contains(this);
162     }
163 
validateVersionNumbersNotNegative()164     private void validateVersionNumbersNotNegative() {
165         if (mMajor < 0 || mMinor < 0 || mPatch < 0) {
166             throw new IllegalArgumentException("Version numbers can not be negative.");
167         }
168     }
169 }
170