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.testapp; 18 19 import com.android.queryable.Queryable; 20 import com.android.queryable.info.ActivityInfo; 21 import com.android.queryable.info.ServiceInfo; 22 import com.android.queryable.queries.ActivityQuery; 23 import com.android.queryable.queries.BooleanQuery; 24 import com.android.queryable.queries.BooleanQueryHelper; 25 import com.android.queryable.queries.BundleQuery; 26 import com.android.queryable.queries.BundleQueryHelper; 27 import com.android.queryable.queries.IntegerQuery; 28 import com.android.queryable.queries.IntegerQueryHelper; 29 import com.android.queryable.queries.ServiceQuery; 30 import com.android.queryable.queries.SetQuery; 31 import com.android.queryable.queries.SetQueryHelper; 32 import com.android.queryable.queries.StringQuery; 33 import com.android.queryable.queries.StringQueryHelper; 34 35 /** Builder for progressively building {@link TestApp} queries. */ 36 public final class TestAppQueryBuilder implements Queryable { 37 private final TestAppProvider mProvider; 38 39 StringQueryHelper<TestAppQueryBuilder> mPackageName = new StringQueryHelper<>(this); 40 BundleQueryHelper<TestAppQueryBuilder> mMetadata = new BundleQueryHelper<>(this); 41 IntegerQueryHelper<TestAppQueryBuilder> mMinSdkVersion = new IntegerQueryHelper<>(this); 42 IntegerQueryHelper<TestAppQueryBuilder> mMaxSdkVersion = new IntegerQueryHelper<>(this); 43 IntegerQueryHelper<TestAppQueryBuilder> mTargetSdkVersion = new IntegerQueryHelper<>(this); 44 SetQueryHelper<TestAppQueryBuilder, String, StringQuery<?>> mPermissions = 45 new SetQueryHelper<>(this); 46 BooleanQueryHelper<TestAppQueryBuilder> mTestOnly = new BooleanQueryHelper<>(this); 47 SetQueryHelper<TestAppQueryBuilder, ActivityInfo, ActivityQuery<?>> mActivities = 48 new SetQueryHelper<>(this); 49 SetQueryHelper<TestAppQueryBuilder, ServiceInfo, ServiceQuery<?>> mServices = 50 new SetQueryHelper<>(this); 51 StringQueryHelper<TestAppQueryBuilder> mSharedUserId = new StringQueryHelper<>(this); 52 TestAppQueryBuilder(TestAppProvider provider)53 TestAppQueryBuilder(TestAppProvider provider) { 54 if (provider == null) { 55 throw new NullPointerException(); 56 } 57 mProvider = provider; 58 } 59 60 /** 61 * Query for a {@link TestApp} with a given package name. 62 * 63 * <p>Only use this filter when you are relying specifically on the package name itself. If you 64 * are relying on features you know the {@link TestApp} with that package name has, query for 65 * those features directly. 66 */ wherePackageName()67 public StringQuery<TestAppQueryBuilder> wherePackageName() { 68 return mPackageName; 69 } 70 71 /** 72 * Query for a {@link TestApp} by metadata. 73 */ whereMetadata()74 public BundleQuery<TestAppQueryBuilder> whereMetadata() { 75 return mMetadata; 76 } 77 78 /** 79 * Query for a {@link TestApp} by minSdkVersion. 80 */ whereMinSdkVersion()81 public IntegerQuery<TestAppQueryBuilder> whereMinSdkVersion() { 82 return mMinSdkVersion; 83 } 84 85 /** 86 * Query for a {@link TestApp} by maxSdkVersion. 87 */ whereMaxSdkVersion()88 public IntegerQuery<TestAppQueryBuilder> whereMaxSdkVersion() { 89 return mMaxSdkVersion; 90 } 91 92 /** 93 * Query for a {@link TestApp} by targetSdkVersion. 94 */ whereTargetSdkVersion()95 public IntegerQuery<TestAppQueryBuilder> whereTargetSdkVersion() { 96 return mTargetSdkVersion; 97 } 98 99 /** 100 * Query for a {@link TestApp} by declared permissions. 101 */ wherePermissions()102 public SetQuery<TestAppQueryBuilder, String, StringQuery<?>> wherePermissions() { 103 return mPermissions; 104 } 105 106 /** 107 * Query for a {@link TestApp} by the testOnly attribute. 108 */ whereTestOnly()109 public BooleanQuery<TestAppQueryBuilder> whereTestOnly() { 110 return mTestOnly; 111 } 112 113 /** 114 * Query for a {@link TestApp} by its sharedUserId; 115 */ whereSharedUserId()116 public StringQuery<TestAppQueryBuilder> whereSharedUserId() { 117 return mSharedUserId; 118 } 119 120 /** 121 * Query for a {@link TestApp} by its activities. 122 */ whereActivities()123 public SetQuery<TestAppQueryBuilder, ActivityInfo, ActivityQuery<?>> whereActivities() { 124 return mActivities; 125 } 126 127 /** 128 * Query for a {@link TestApp} by its services. 129 */ whereServices()130 public SetQuery<TestAppQueryBuilder, ServiceInfo, ServiceQuery<?>> whereServices() { 131 return mServices; 132 } 133 134 /** 135 * Get the {@link TestApp} matching the query. 136 * 137 * @throws NotFoundException if there is no matching @{link TestApp}. 138 */ get()139 public TestApp get() { 140 // TODO(scottjonathan): Provide instructions on adding the TestApp if the query fails 141 return new TestApp(resolveQuery()); 142 } 143 resolveQuery()144 private TestAppDetails resolveQuery() { 145 for (TestAppDetails details : mProvider.testApps()) { 146 if (!matches(details)) { 147 continue; 148 } 149 150 mProvider.markTestAppUsed(details); 151 return details; 152 } 153 154 throw new NotFoundException(this); 155 } 156 matches(TestAppDetails details)157 private boolean matches(TestAppDetails details) { 158 if (!StringQueryHelper.matches(mPackageName, details.mApp.getPackageName())) { 159 return false; 160 } 161 162 if (!BundleQueryHelper.matches(mMetadata, details.mMetadata)) { 163 return false; 164 } 165 166 if (!IntegerQueryHelper.matches( 167 mMinSdkVersion, details.mApp.getUsesSdk().getMinSdkVersion())) { 168 return false; 169 } 170 171 if (!IntegerQueryHelper.matches( 172 mMaxSdkVersion, details.mApp.getUsesSdk().getMaxSdkVersion())) { 173 return false; 174 } 175 176 if (!IntegerQueryHelper.matches( 177 mTargetSdkVersion, details.mApp.getUsesSdk().getTargetSdkVersion())) { 178 return false; 179 } 180 181 if (!SetQueryHelper.matches(mActivities, details.mActivities)) { 182 return false; 183 } 184 185 if (!SetQueryHelper.matches(mServices, details.mServices)) { 186 return false; 187 } 188 189 if (!SetQueryHelper.matches(mPermissions, details.mPermissions)) { 190 return false; 191 } 192 193 if (!BooleanQueryHelper.matches(mTestOnly, details.mApp.getTestOnly())) { 194 return false; 195 } 196 197 if (mSharedUserId.isEmpty()) { 198 if (details.sharedUserId() != null) { 199 return false; 200 } 201 } else { 202 if (!StringQueryHelper.matches(mSharedUserId, details.sharedUserId())) { 203 return false; 204 } 205 } 206 207 if (details.mMetadata.getString("testapp-package-query-only", "false") 208 .equals("true")) { 209 if (!mPackageName.isQueryingForExactMatch()) { 210 return false; 211 } 212 } 213 214 return true; 215 } 216 217 @Override describeQuery(String fieldName)218 public String describeQuery(String fieldName) { 219 return "{" + Queryable.joinQueryStrings( 220 mPackageName.describeQuery("packageName"), 221 mMetadata.describeQuery("metadata"), 222 mMinSdkVersion.describeQuery("minSdkVersion"), 223 mMaxSdkVersion.describeQuery("maxSdkVersion"), 224 mTargetSdkVersion.describeQuery("targetSdkVersion"), 225 mActivities.describeQuery("activities"), 226 mServices.describeQuery("services"), 227 mPermissions.describeQuery("permissions"), 228 mSharedUserId.describeQuery("sharedUserId"), 229 mTestOnly.describeQuery("testOnly") 230 ) + "}"; 231 } 232 } 233