1 /*
2  * Copyright (C) 2020 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.car.user;
18 
19 import static com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport.BOILERPLATE_CODE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.SystemApi;
25 import android.os.Parcelable;
26 import android.os.UserManager;
27 
28 import com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport;
29 import com.android.car.internal.util.DataClass;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 
34 /**
35  * User switch results.
36  *
37  * @hide
38  */
39 @DataClass(
40         genToString = true,
41         genHiddenConstructor = true,
42         genHiddenConstDefs = true)
43 @SystemApi
44 public final class UserSwitchResult implements Parcelable, OperationResult {
45 
46     /**
47      * When user switch is successful for both HAL and Android.
48      */
49     @Status
50     public static final int STATUS_SUCCESSFUL = CommonResults.STATUS_SUCCESSFUL;
51 
52     /**
53      * When user switch is only successful for Hal but not for Android. Hal user switch rollover
54      * message have been sent.
55      */
56     @Status
57     public static final int STATUS_ANDROID_FAILURE = CommonResults.STATUS_ANDROID_FAILURE;
58 
59     /**
60      * When user switch fails for HAL. User switch for Android is not called.
61      */
62     @Status
63     public static final int STATUS_HAL_FAILURE = CommonResults.STATUS_HAL_FAILURE;
64 
65     /**
66      * When user switch fails for HAL for some internal error. User switch for Android is not
67      * called.
68      */
69     @Status
70     public static final int STATUS_HAL_INTERNAL_FAILURE = CommonResults.STATUS_HAL_INTERNAL_FAILURE;
71 
72     /**
73      * When given parameters or environment states are invalid for switching user. HAL or Android
74      * user switch is not requested.
75      */
76     @Status
77     public static final int STATUS_INVALID_REQUEST = CommonResults.STATUS_INVALID_REQUEST;
78 
79     /**
80      * When user switch fails because of driving safety UX restrictions.
81      */
82     @Status
83     public static final int STATUS_UX_RESTRICTION_FAILURE =
84             CommonResults.STATUS_UX_RESTRICTION_FAILURE;
85 
86     /**
87      * When target user is same as current user.
88      */
89     @Status
90     public static final int STATUS_OK_USER_ALREADY_IN_FOREGROUND =
91             CommonResults.LAST_COMMON_STATUS + 1;
92 
93     /**
94      * When another user switch request for the same target user is in process.
95      */
96     @Status
97     public static final int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO =
98             CommonResults.LAST_COMMON_STATUS + 2;
99 
100     /**
101      * When another user switch request for a new different target user is received. Previous
102      * request is abandoned.
103      */
104     @Status
105     public static final int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST =
106             CommonResults.LAST_COMMON_STATUS + 3;
107 
108     /**
109      * When switching users is currently not allowed for the user this process is running under.
110      */
111     @Status
112     public static final int STATUS_NOT_SWITCHABLE =
113             CommonResults.LAST_COMMON_STATUS + 4;
114 
115     /**
116      * When logout was called but the current user was not switched by a device admin.
117      */
118     @Status
119     public static final int STATUS_NOT_LOGGED_IN =
120             CommonResults.LAST_COMMON_STATUS + 5;
121 
122     /**
123      * Gets the user switch result status.
124      *
125      * @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
126      *         {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
127      *         {@link UserSwitchResult#STATUS_HAL_FAILURE},
128      *         {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
129      *         {@link UserSwitchResult#STATUS_INVALID_REQUEST},
130      *         {@link UserSwitchResult#STATUS_UX_RESTRICTION_FAILURE},
131      *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
132      *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
133      *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST},
134      *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}, or
135      *         {@link UserSwitchResult#STATUS_NOT_LOGGED_IN}.
136      */
137     private final @Status int mStatus;
138 
139     // TODO(b/214443810): codegen generates call to writeInteger() / readInteger(), we need to
140     // manually change to writeInt() / readInt()
141     /**
142      * Gets the failure status returned by {@link UserManager} when the {@link #getStatus() status}
143      * is {@link #STATUS_ANDROID_FAILURE}.
144      *
145      * @return {@code USER_OPERATION_ERROR_} constants defined by {@link UserManager}, or
146      * {@code null} when the {@link #getStatus() status} is not {@link #STATUS_ANDROID_FAILURE}.
147      */
148     @Nullable
149     private final Integer mAndroidFailureStatus;
150 
151     /**
152      * Gets the error message, if any.
153      */
154     @Nullable
155     private final String mErrorMessage;
156 
157     @Override
isSuccess()158     public boolean isSuccess() {
159         return mStatus == STATUS_SUCCESSFUL || mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND;
160     }
161 
162     /** @hide */
UserSwitchResult(@tatus int status, @Nullable String errorMessage)163     public UserSwitchResult(@Status int status, @Nullable String errorMessage) {
164         this(status, /* androidFailureStatus= */ null, errorMessage);
165     }
166 
167     // NOTE: codegen generates this method, but without @ExcludeFromCodeCoverageGeneratedReport
168     @Override
169     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
describeContents()170     public int describeContents() {
171         return 0;
172     }
173 
174 
175 
176     // Code below generated by codegen v1.0.23.
177     //
178     // DO NOT MODIFY!
179     // CHECKSTYLE:OFF Generated code
180     //
181     // To regenerate run:
182     // $ codegen $ANDROID_BUILD_TOP/packages/services/Car/car-lib/src/android/car/user/UserSwitchResult.java
183     // Added AddedInOrBefore or ApiRequirement Annotation manually
184     //
185     // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
186     //   Settings > Editor > Code Style > Formatter Control
187     //@formatter:off
188 
189 
190     /** @hide */
191     @IntDef(prefix = "STATUS_", value = {
192         STATUS_SUCCESSFUL,
193         STATUS_ANDROID_FAILURE,
194         STATUS_HAL_FAILURE,
195         STATUS_HAL_INTERNAL_FAILURE,
196         STATUS_INVALID_REQUEST,
197         STATUS_UX_RESTRICTION_FAILURE,
198         STATUS_OK_USER_ALREADY_IN_FOREGROUND,
199         STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO,
200         STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST,
201         STATUS_NOT_SWITCHABLE,
202         STATUS_NOT_LOGGED_IN
203     })
204     @Retention(RetentionPolicy.SOURCE)
205     @DataClass.Generated.Member
206     public @interface Status {}
207 
208     @DataClass.Generated.Member
209     @ExcludeFromCodeCoverageGeneratedReport(reason = BOILERPLATE_CODE)
210     @NonNull
statusToString(@tatus int value)211     public static String statusToString(@Status int value) {
212         switch (value) {
213             case STATUS_SUCCESSFUL:
214                     return "STATUS_SUCCESSFUL";
215             case STATUS_ANDROID_FAILURE:
216                     return "STATUS_ANDROID_FAILURE";
217             case STATUS_HAL_FAILURE:
218                     return "STATUS_HAL_FAILURE";
219             case STATUS_HAL_INTERNAL_FAILURE:
220                     return "STATUS_HAL_INTERNAL_FAILURE";
221             case STATUS_INVALID_REQUEST:
222                     return "STATUS_INVALID_REQUEST";
223             case STATUS_UX_RESTRICTION_FAILURE:
224                     return "STATUS_UX_RESTRICTION_FAILURE";
225             case STATUS_OK_USER_ALREADY_IN_FOREGROUND:
226                     return "STATUS_OK_USER_ALREADY_IN_FOREGROUND";
227             case STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO:
228                     return "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO";
229             case STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST:
230                     return "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST";
231             case STATUS_NOT_SWITCHABLE:
232                     return "STATUS_NOT_SWITCHABLE";
233             case STATUS_NOT_LOGGED_IN:
234                     return "STATUS_NOT_LOGGED_IN";
235             default: return Integer.toHexString(value);
236         }
237     }
238 
239     /**
240      * Creates a new UserSwitchResult.
241      *
242      * @param status
243      *   Gets the user switch result status.
244      *
245      *   @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
246      *           {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
247      *           {@link UserSwitchResult#STATUS_HAL_FAILURE},
248      *           {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
249      *           {@link UserSwitchResult#STATUS_INVALID_REQUEST},
250      *           {@link UserSwitchResult#STATUS_UX_RESTRICTION_FAILURE},
251      *           {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
252      *           {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
253      *           {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST},
254      *           {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}, or
255      *           {@link UserSwitchResult#STATUS_NOT_LOGGED_IN}.
256      * @param androidFailureStatus
257      *   Gets the failure status returned by {@link UserManager} when the {@link #getStatus() status}
258      *   is {@link #STATUS_ANDROID_FAILURE}.
259      *
260      *   @return {@code USER_OPERATION_ERROR_} constants defined by {@link UserManager}, or
261      *   {@code null} when the {@link #getStatus() status} is not {@link #STATUS_ANDROID_FAILURE}.
262      * @param errorMessage
263      *   Gets the error message, if any.
264      * @hide
265      */
266     @DataClass.Generated.Member
UserSwitchResult( @tatus int status, @Nullable Integer androidFailureStatus, @Nullable String errorMessage)267     public UserSwitchResult(
268             @Status int status,
269             @Nullable Integer androidFailureStatus,
270             @Nullable String errorMessage) {
271         this.mStatus = status;
272 
273         if (!(mStatus == STATUS_SUCCESSFUL)
274                 && !(mStatus == STATUS_ANDROID_FAILURE)
275                 && !(mStatus == STATUS_HAL_FAILURE)
276                 && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
277                 && !(mStatus == STATUS_INVALID_REQUEST)
278                 && !(mStatus == STATUS_UX_RESTRICTION_FAILURE)
279                 && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
280                 && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
281                 && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
282                 && !(mStatus == STATUS_NOT_SWITCHABLE)
283                 && !(mStatus == STATUS_NOT_LOGGED_IN)) {
284             throw new java.lang.IllegalArgumentException(
285                     "status was " + mStatus + " but must be one of: "
286                             + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
287                             + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
288                             + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
289                             + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
290                             + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + "), "
291                             + "STATUS_UX_RESTRICTION_FAILURE(" + STATUS_UX_RESTRICTION_FAILURE + "), "
292                             + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
293                             + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
294                             + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
295                             + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + "), "
296                             + "STATUS_NOT_LOGGED_IN(" + STATUS_NOT_LOGGED_IN + ")");
297         }
298 
299         this.mAndroidFailureStatus = androidFailureStatus;
300         this.mErrorMessage = errorMessage;
301 
302         // onConstructed(); // You can define this method to get a callback
303     }
304 
305     /**
306      * Gets the user switch result status.
307      *
308      * @return either {@link UserSwitchResult#STATUS_SUCCESSFUL},
309      *         {@link UserSwitchResult#STATUS_ANDROID_FAILURE},
310      *         {@link UserSwitchResult#STATUS_HAL_FAILURE},
311      *         {@link UserSwitchResult#STATUS_HAL_INTERNAL_FAILURE},
312      *         {@link UserSwitchResult#STATUS_INVALID_REQUEST},
313      *         {@link UserSwitchResult#STATUS_UX_RESTRICTION_FAILURE},
314      *         {@link UserSwitchResult#STATUS_OK_USER_ALREADY_IN_FOREGROUND},
315      *         {@link UserSwitchResult#STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO},
316      *         {@link UserSwitchResult#STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST},
317      *         {@link UserSwitchResult#STATUS_NOT_SWITCHABLE}, or
318      *         {@link UserSwitchResult#STATUS_NOT_LOGGED_IN}.
319      */
320     @DataClass.Generated.Member
getStatus()321     public @Status int getStatus() {
322         return mStatus;
323     }
324 
325     /**
326      * Gets the failure status returned by {@link UserManager} when the {@link #getStatus() status}
327      * is {@link #STATUS_ANDROID_FAILURE}.
328      *
329      * @return {@code USER_OPERATION_ERROR_} constants defined by {@link UserManager}, or
330      * {@code null} when the {@link #getStatus() status} is not {@link #STATUS_ANDROID_FAILURE}.
331      */
332     @DataClass.Generated.Member
getAndroidFailureStatus()333     public @Nullable Integer getAndroidFailureStatus() {
334         return mAndroidFailureStatus;
335     }
336 
337     /**
338      * Gets the error message, if any.
339      */
340     @DataClass.Generated.Member
getErrorMessage()341     public @Nullable String getErrorMessage() {
342         return mErrorMessage;
343     }
344 
345     @Override
346     @DataClass.Generated.Member
toString()347     public String toString() {
348         // You can override field toString logic by defining methods like:
349         // String fieldNameToString() { ... }
350 
351         return "UserSwitchResult { " +
352                 "status = " + statusToString(mStatus) + ", " +
353                 "androidFailureStatus = " + mAndroidFailureStatus + ", " +
354                 "errorMessage = " + mErrorMessage +
355         " }";
356     }
357 
358     @Override
359     @DataClass.Generated.Member
writeToParcel(@ndroid.annotation.NonNull android.os.Parcel dest, int flags)360     public void writeToParcel(@android.annotation.NonNull android.os.Parcel dest, int flags) {
361         // You can override field parcelling by defining methods like:
362         // void parcelFieldName(Parcel dest, int flags) { ... }
363 
364         byte flg = 0;
365         if (mAndroidFailureStatus != null) flg |= 0x2;
366         if (mErrorMessage != null) flg |= 0x4;
367         dest.writeByte(flg);
368         dest.writeInt(mStatus);
369         if (mAndroidFailureStatus != null) dest.writeInt(mAndroidFailureStatus);
370         if (mErrorMessage != null) dest.writeString(mErrorMessage);
371     }
372 
373     /** @hide */
374     @SuppressWarnings({"unchecked", "RedundantCast"})
375     @DataClass.Generated.Member
UserSwitchResult(@ndroid.annotation.NonNull android.os.Parcel in)376     /* package-private */ UserSwitchResult(@android.annotation.NonNull android.os.Parcel in) {
377         // You can override field unparcelling by defining methods like:
378         // static FieldType unparcelFieldName(Parcel in) { ... }
379 
380         byte flg = in.readByte();
381         int status = in.readInt();
382         Integer androidFailureStatus = (flg & 0x2) == 0 ? null : (Integer) in.readInt();
383         String errorMessage = (flg & 0x4) == 0 ? null : in.readString();
384 
385         this.mStatus = status;
386 
387         if (!(mStatus == STATUS_SUCCESSFUL)
388                 && !(mStatus == STATUS_ANDROID_FAILURE)
389                 && !(mStatus == STATUS_HAL_FAILURE)
390                 && !(mStatus == STATUS_HAL_INTERNAL_FAILURE)
391                 && !(mStatus == STATUS_INVALID_REQUEST)
392                 && !(mStatus == STATUS_UX_RESTRICTION_FAILURE)
393                 && !(mStatus == STATUS_OK_USER_ALREADY_IN_FOREGROUND)
394                 && !(mStatus == STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO)
395                 && !(mStatus == STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST)
396                 && !(mStatus == STATUS_NOT_SWITCHABLE)
397                 && !(mStatus == STATUS_NOT_LOGGED_IN)) {
398             throw new java.lang.IllegalArgumentException(
399                     "status was " + mStatus + " but must be one of: "
400                             + "STATUS_SUCCESSFUL(" + STATUS_SUCCESSFUL + "), "
401                             + "STATUS_ANDROID_FAILURE(" + STATUS_ANDROID_FAILURE + "), "
402                             + "STATUS_HAL_FAILURE(" + STATUS_HAL_FAILURE + "), "
403                             + "STATUS_HAL_INTERNAL_FAILURE(" + STATUS_HAL_INTERNAL_FAILURE + "), "
404                             + "STATUS_INVALID_REQUEST(" + STATUS_INVALID_REQUEST + "), "
405                             + "STATUS_UX_RESTRICTION_FAILURE(" + STATUS_UX_RESTRICTION_FAILURE + "), "
406                             + "STATUS_OK_USER_ALREADY_IN_FOREGROUND(" + STATUS_OK_USER_ALREADY_IN_FOREGROUND + "), "
407                             + "STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO(" + STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO + "), "
408                             + "STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST(" + STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST + "), "
409                             + "STATUS_NOT_SWITCHABLE(" + STATUS_NOT_SWITCHABLE + "), "
410                             + "STATUS_NOT_LOGGED_IN(" + STATUS_NOT_LOGGED_IN + ")");
411         }
412 
413         this.mAndroidFailureStatus = androidFailureStatus;
414         this.mErrorMessage = errorMessage;
415 
416         // onConstructed(); // You can define this method to get a callback
417     }
418 
419     @DataClass.Generated.Member
420     public static final @android.annotation.NonNull Parcelable.Creator<UserSwitchResult> CREATOR
421             = new Parcelable.Creator<UserSwitchResult>() {
422         @Override
423         public UserSwitchResult[] newArray(int size) {
424             return new UserSwitchResult[size];
425         }
426 
427         @Override
428         public UserSwitchResult createFromParcel(@android.annotation.NonNull android.os.Parcel in) {
429             return new UserSwitchResult(in);
430         }
431     };
432 
433     @DataClass.Generated(
434             time = 1673057752058L,
435             codegenVersion = "1.0.23",
436             sourceFile = "packages/services/Car/car-lib/src/android/car/user/UserSwitchResult.java",
437             inputSignatures = "public static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_SUCCESSFUL\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_ANDROID_FAILURE\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_HAL_FAILURE\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_HAL_INTERNAL_FAILURE\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_INVALID_REQUEST\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_UX_RESTRICTION_FAILURE\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_OK_USER_ALREADY_IN_FOREGROUND\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_TARGET_USER_ALREADY_BEING_SWITCHED_TO\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_TARGET_USER_ABANDONED_DUE_TO_A_NEW_REQUEST\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_NOT_SWITCHABLE\npublic static final @android.car.user.UserSwitchResult.Status @android.car.annotation.AddedInOrBefore int STATUS_NOT_LOGGED_IN\nprivate final @android.car.user.UserSwitchResult.Status int mStatus\nprivate final @android.annotation.Nullable java.lang.Integer mAndroidFailureStatus\nprivate final @android.annotation.Nullable java.lang.String mErrorMessage\npublic @java.lang.Override @android.car.annotation.AddedInOrBefore boolean isSuccess()\npublic @java.lang.Override @com.android.car.internal.ExcludeFromCodeCoverageGeneratedReport @android.car.annotation.AddedInOrBefore int describeContents()\nclass UserSwitchResult extends java.lang.Object implements [android.os.Parcelable, android.car.user.OperationResult]\n@com.android.car.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
438     @Deprecated
__metadata()439     private void __metadata() {}
440 
441 
442     //@formatter:on
443     // End of generated code
444 
445 }
446