1 /*
2  * Copyright (C) 2023 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;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.SystemApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 
25 import java.lang.annotation.Retention;
26 import java.lang.annotation.RetentionPolicy;
27 
28 /**
29  * Represents the state of HealthConnect data as it goes through one of the following operations:
30  * <li>Data Restore: fetching and restoring the data either from the cloud or from another device.
31  * <li>Data Migration: migrating the data from the app using the data-migration APIs: {@link
32  *     HealthConnectManager#startMigration}, {@link HealthConnectManager#writeMigrationData}, and
33  *     {@link HealthConnectManager#finishMigration}
34  *
35  * @hide
36  */
37 @SystemApi
38 public final class HealthConnectDataState implements Parcelable {
39     /**
40      * The default idle state of HealthConnect data restore process. This states means that nothing
41      * related to the data restore process is undergoing. {@link #getDataRestoreError()} could
42      * return an error for previous restoration attempt.
43      *
44      * <p>See also {@link DataRestoreState}
45      *
46      * @hide
47      */
48     @SystemApi public static final int RESTORE_STATE_IDLE = 0;
49 
50     /**
51      * The HealthConnect data is pending restoration. The system is in the process of fetching /
52      * staging the remote data on this device. Once the data has been fetched and staged for
53      * restoration an attempt will be made to restore the data. So, this will follow with {@link
54      * #RESTORE_STATE_IN_PROGRESS} state.
55      *
56      * <p>See also {@link DataRestoreState}
57      *
58      * @hide
59      */
60     @SystemApi public static final int RESTORE_STATE_PENDING = 1;
61 
62     /**
63      * The HealthConnect staged data is being restored. On a successful restore the data will be
64      * available for use on this device.
65      *
66      * <p>After the restore process is finished, we'll come back to the {@link #RESTORE_STATE_IDLE}.
67      *
68      * <p>See also {@link DataRestoreState}
69      *
70      * @hide
71      */
72     @SystemApi public static final int RESTORE_STATE_IN_PROGRESS = 2;
73 
74     /** @hide */
75     @Retention(RetentionPolicy.SOURCE)
76     @IntDef({RESTORE_STATE_IDLE, RESTORE_STATE_PENDING, RESTORE_STATE_IN_PROGRESS})
77     public @interface DataRestoreState {}
78 
79     /**
80      * No error.
81      *
82      * @hide
83      */
84     @SystemApi public static final int RESTORE_ERROR_NONE = 0;
85 
86     /**
87      * An unknown error caused a failure in restoring the data.
88      *
89      * <p>This is a non-recoverable error.
90      *
91      * @hide
92      */
93     @SystemApi public static final int RESTORE_ERROR_UNKNOWN = 1;
94 
95     /**
96      * An error was encountered fetching the remote HealthConnect data.
97      *
98      * <p>This is a non-recoverable error.
99      *
100      * <p>For instance, this could have been caused by a network issue leading to download failure.
101      * In such a case a retry would've been attempted, but eventually that failed as well.
102      *
103      * @hide
104      */
105     @SystemApi public static final int RESTORE_ERROR_FETCHING_DATA = 2;
106 
107     /**
108      * The fetched remote data could not be restored because the current HealthConnect version on
109      * the device is behind the staged data version.
110      *
111      * <p>This is a recoverable error.
112      *
113      * <p>Until the module has been updated we'll be waiting in the {@link #RESTORE_STATE_PENDING}
114      * state. Once the HealthConnect version on the device is updated and rebooted then the restore
115      * will be attempted on the same device reboot.
116      *
117      * @hide
118      */
119     @SystemApi public static final int RESTORE_ERROR_VERSION_DIFF = 3;
120 
121     /** @hide */
122     @Retention(RetentionPolicy.SOURCE)
123     @IntDef({
124         RESTORE_ERROR_NONE,
125         RESTORE_ERROR_UNKNOWN,
126         RESTORE_ERROR_FETCHING_DATA,
127         RESTORE_ERROR_VERSION_DIFF
128     })
129     public @interface DataRestoreError {}
130 
131     /**
132      * The starting default state for the Migration process.
133      *
134      * <p>We'll begin in this state irrespective of whether there's an app installed that can
135      * perform Migration. If there's no such app installed then we stay in this state. However, if
136      * an installed app can be upgraded to become Migration-aware, then we'll move to the {@link
137      * #MIGRATION_STATE_APP_UPGRADE_REQUIRED} state. Please see {@link
138      * #MIGRATION_STATE_APP_UPGRADE_REQUIRED} for more info.
139      *
140      * <p>See also {@link DataMigrationState}
141      *
142      * @hide
143      */
144     @SystemApi public static final int MIGRATION_STATE_IDLE = 0;
145 
146     /**
147      * This reflects that the app needs an upgrade before it can start the Migration process.
148      *
149      * <p>This happens when the module finds out that there's an installed app that can perform the
150      * Migration process once it has been upgraded to the correct version. Once such an app is
151      * available then we'll move back to the {@link #MIGRATION_STATE_IDLE} state.
152      *
153      * <p>We can come here only from the {@link #MIGRATION_STATE_IDLE} state.
154      *
155      * <p>See also {@link DataMigrationState}
156      *
157      * @hide
158      */
159     @SystemApi public static final int MIGRATION_STATE_APP_UPGRADE_REQUIRED = 1;
160 
161     /**
162      * This reflects that the module needs an upgrade to handle the Migration process.
163      *
164      * <p>This happens when the version set by the caller is ahead of the HealthConnect module. Once
165      * the module has updated to a version greater or equal to the said set version, then we'll move
166      * to the {@link #MIGRATION_STATE_ALLOWED} state from where the Migration process can start.
167      *
168      * <p>We can come here only from the {@link #MIGRATION_STATE_IDLE} state.
169      *
170      * <p>See also {@link DataMigrationState}
171      *
172      * @hide
173      */
174     @SystemApi public static final int MIGRATION_STATE_MODULE_UPGRADE_REQUIRED = 2;
175 
176     /**
177      * We are in the process of integrating the data shared by the app using the {@link
178      * HealthConnectManager#writeMigrationData} API.
179      *
180      * <p>We get into this state when the app makes the {@link HealthConnectManager#startMigration}
181      * call.
182      *
183      * <p>We can come here from either {@link #MIGRATION_STATE_ALLOWED} or {@link
184      * #MIGRATION_STATE_IDLE} states when {@link HealthConnectManager#startMigration} is called.
185      *
186      * <p>From here we can go to either {@link #MIGRATION_STATE_ALLOWED} OR {@link
187      * #MIGRATION_STATE_COMPLETE} state.
188      *
189      * <p>All other HealthConnect APIs unrelated to Migration are blocked while we are in this
190      * state. For more info on this please see
191      *
192      * <p>See also {@link DataMigrationState}
193      *
194      * @hide
195      */
196     @SystemApi public static final int MIGRATION_STATE_IN_PROGRESS = 3;
197 
198     /**
199      * The Migration is now allowed and is waiting to start or resume.
200      *
201      * <p>We can come to this state from any of the following states:
202      *
203      * <ul>
204      *   <li>{@link #MIGRATION_STATE_IDLE} if the module is ready to
205      *   <li>{@link #MIGRATION_STATE_MODULE_UPGRADE_REQUIRED} when the module upgrades to the
206      *       minimum required version.
207      *   <li>{@link #MIGRATION_STATE_IN_PROGRESS} in case of a timeout of 12 hours.
208      * </ul>
209      *
210      * <p>From this state we can go to either {@link #MIGRATION_STATE_IN_PROGRESS} or {@link
211      * #MIGRATION_STATE_COMPLETE} (in case of timeout of 15 days).
212      *
213      * <p>See also {@link DataMigrationState}
214      *
215      * @hide
216      */
217     @SystemApi public static final int MIGRATION_STATE_ALLOWED = 4;
218 
219     /**
220      * This is the final state for the Migration process. We can come here from any other state:
221      *
222      * <ul>
223      *   <li>From {@link #MIGRATION_STATE_IDLE} after a timeout of 30 days.
224      *   <li>From {@link #MIGRATION_STATE_MODULE_UPGRADE_REQUIRED} after a timeout of 15 days.
225      *   <li>From {@link #MIGRATION_STATE_IN_PROGRESS} when {@link
226      *       HealthConnectManager#finishMigration} is called.
227      *   <li>From {@link #MIGRATION_STATE_ALLOWED} after a timeout of 15 days.
228      * </ul>
229      *
230      * <p>See also {@link DataMigrationState}
231      *
232      * @hide
233      */
234     @SystemApi public static final int MIGRATION_STATE_COMPLETE = 5;
235 
236     /** @hide */
237     @Retention(RetentionPolicy.SOURCE)
238     @IntDef({
239         MIGRATION_STATE_IDLE,
240         MIGRATION_STATE_APP_UPGRADE_REQUIRED,
241         MIGRATION_STATE_MODULE_UPGRADE_REQUIRED,
242         MIGRATION_STATE_IN_PROGRESS,
243         MIGRATION_STATE_ALLOWED,
244         MIGRATION_STATE_COMPLETE
245     })
246     public @interface DataMigrationState {}
247 
248     private final @DataRestoreState int mDataRestoreState;
249     private final @DataRestoreError int mDataRestoreError;
250     private final @DataMigrationState int mDataMigrationState;
251 
252     /**
253      * The state of the HealthConnect data as it goes through the Data Restore process.
254      *
255      * <p>See also {@link DataRestoreState}
256      */
getDataRestoreState()257     public @DataRestoreState int getDataRestoreState() {
258         return mDataRestoreState;
259     }
260 
261     /**
262      * Get error encountered at the time of calling this API as we try to fetch and restore the
263      * remote HealthConnect data.
264      *
265      * <p>Since we stop at the first encounter of an error there can be only one error at any time.
266      *
267      * <p>Some of the errors are recoverable while others are non-recoverable. Please see {@link
268      * DataRestoreError} for more details on which errors are recoverable and how to recover from
269      * them.
270      */
getDataRestoreError()271     public @DataRestoreError int getDataRestoreError() {
272         return mDataRestoreError;
273     }
274 
275     /**
276      * The state of the HealthConnect data as it goes through the Data Migration process.
277      *
278      * <p>See also {@link DataMigrationState}
279      */
getDataMigrationState()280     public @DataMigrationState int getDataMigrationState() {
281         return mDataMigrationState;
282     }
283 
284     /** @hide */
HealthConnectDataState( @ataRestoreState int dataRestoreState, @DataRestoreError int dataRestoreError, @DataMigrationState int dataMigrationState)285     public HealthConnectDataState(
286             @DataRestoreState int dataRestoreState,
287             @DataRestoreError int dataRestoreError,
288             @DataMigrationState int dataMigrationState) {
289         this.mDataRestoreState = dataRestoreState;
290         this.mDataRestoreError = dataRestoreError;
291         this.mDataMigrationState = dataMigrationState;
292     }
293 
294     @NonNull
295     public static final Creator<HealthConnectDataState> CREATOR =
296             new Creator<>() {
297                 @Override
298                 public HealthConnectDataState createFromParcel(Parcel in) {
299                     return new HealthConnectDataState(in);
300                 }
301 
302                 @Override
303                 public HealthConnectDataState[] newArray(int size) {
304                     return new HealthConnectDataState[size];
305                 }
306             };
307 
308     @Override
describeContents()309     public int describeContents() {
310         return 0;
311     }
312 
313     @Override
writeToParcel(@onNull Parcel dest, int flags)314     public void writeToParcel(@NonNull Parcel dest, int flags) {
315         dest.writeInt(mDataRestoreState);
316         dest.writeInt(mDataRestoreError);
317         dest.writeInt(mDataMigrationState);
318     }
319 
HealthConnectDataState(Parcel in)320     private HealthConnectDataState(Parcel in) {
321         mDataRestoreState = in.readInt();
322         mDataRestoreError = in.readInt();
323         mDataMigrationState = in.readInt();
324     }
325 }
326