1 /*
2  * Copyright (C) 2021 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 com.android.bedstead.enterprise.annotations;
18 
19 import com.android.bedstead.harrier.HarrierRule
20 import com.android.bedstead.harrier.UserType.INITIAL_USER;
21 import com.android.bedstead.harrier.annotations.AnnotationPriorityRunPrecedence.REQUIRE_RUN_ON_PRECEDENCE;
22 import com.android.bedstead.nene.types.OptionalBoolean.ANY;
23 import com.android.bedstead.nene.types.OptionalBoolean.FALSE;
24 
25 import com.android.bedstead.harrier.UserType;
26 import com.android.bedstead.harrier.annotations.RequireFeature
27 import com.android.bedstead.harrier.annotations.meta.EnsureHasProfileAnnotation;
28 import com.android.bedstead.nene.types.OptionalBoolean;
29 import com.android.queryable.annotations.Query;
30 import com.google.auto.value.AutoAnnotation
31 
32 
33 /**
34  * Mark that a test method should run on a user which has a work profile.
35  *
36  * Use of this annotation implies
37  * [RequireFeature("android.software.managed_users", SKIP)].
38  *
39  * Your test configuration may be configured so that this test is only run on a user which has
40  * a work profile. Otherwise, you can use [DeviceState] to ensure that the device enters
41  * the correct state for the method.
42  *
43  * @param forUser Which user type the work profile should be attached to.
44  * @param installInstrumentedApp Whether the instrumented test app should be installed in the work profile.
45  * @param dpcKey The key used to identify the profile owner.
46  *  This can be used with [AdditionalQueryParameters] to modify the requirements for
47  *  the DPC.
48  * @param dpc Requirements for the Profile Owner. Defaults to the default version of RemoteDPC.
49  * @param dpcIsPrimary Whether the profile owner's DPC should be returned by calls to [DeviceState#dpc()].
50  *  Only one device policy controller per test should be marked as primary.
51  * @param isOrganizationOwned Whether the work profile device will be in COPE mode.
52  * @param useParentInstanceOfDpc If true, uses the [DevicePolicyManager#getParentProfileInstance(ComponentName)]
53  *  instance of the dpc when calling to .dpc(). Only used if [dpcIsPrimary] is true.
54  * @param switchedToParentUser Should we ensure that we are switched to the parent of the profile.
55  * @param isQuietModeEnabled Is the profile in quiet mode?
56  * @param priority Priority sets the order that annotations will be resolved.
57  *  Annotations with a lower priority will be resolved before annotations with a higher
58  *  priority.
59  *
60  *  If there is an order requirement between annotations, ensure that the priority of the
61  *  annotation which must be resolved first is lower than the one which must be resolved later.
62  *
63  *  Priority can be set to a [AnnotationPriorityRunPrecedence] constant, or to any [int].
64  */
65 @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
66 @Retention(AnnotationRetention.RUNTIME)
67 @EnsureHasProfileAnnotation(value = "android.os.usertype.profile.MANAGED", hasProfileOwner = true)
68 @RequireFeature("android.software.managed_users")
69 @EnsureHasNoDeviceOwner // TODO: This should only apply on Android R+
70 annotation class EnsureHasWorkProfile(
71     val forUser: UserType = INITIAL_USER,
72     val installInstrumentedApp: OptionalBoolean = ANY,
73     val dpcKey: String = DEFAULT_DPC_KEY,
74     val dpc: Query = Query(),
75     val dpcIsPrimary: Boolean = false,
76     val isOrganizationOwned: Boolean = false,
77     val useParentInstanceOfDpc: Boolean = false,
78     val switchedToParentUser: OptionalBoolean = ANY,
79     val isQuietModeEnabled: OptionalBoolean = FALSE,
80     val priority: Int = ENSURE_HAS_WORK_PROFILE_PRIORITY
81 )
82 
83 const val ENSURE_HAS_WORK_PROFILE_PRIORITY = REQUIRE_RUN_ON_PRECEDENCE - 1
84 
85 const val DEFAULT_DPC_KEY = "profileOwner"
86 
87 /**
88  * Return an instance of the generated class that conforms to the specification of
89  * [EnsureHasWorkProfile]. See [AutoAnnotation].
90  */
ensureHasWorkProfilenull91 fun ensureHasWorkProfile(): EnsureHasWorkProfile {
92     return ensureHasWorkProfile(query())
93 }
94 
95 @AutoAnnotation
ensureHasWorkProfilenull96 private fun ensureHasWorkProfile(dpc: Query): EnsureHasWorkProfile {
97     return AutoAnnotation_EnsureHasWorkProfileKt_ensureHasWorkProfile(dpc)
98 }
99 
100 /**
101  * A workaround to create an [AutoAnnotation] of [EnsureHasWorkProfile]. [AutoAnnotation]
102  * cannot set default values for fields of type Annotation, hence we create an object of [Query]
103  * explicitly to pass as the default value of the [dpc] field.
104  */
querynull105 private fun query(): Query {
106     return HarrierRule::class.java.getAnnotation(Query::class.java)!!
107 }
108