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 android.content.Context; 20 import android.content.IntentFilter; 21 import android.util.Log; 22 23 import com.android.bedstead.nene.TestApis; 24 import com.android.queryable.info.ActivityInfo; 25 import com.android.queryable.info.ServiceInfo; 26 27 import java.io.IOException; 28 import java.io.InputStream; 29 import java.util.HashSet; 30 import java.util.List; 31 import java.util.Set; 32 33 /** Entry point to Test App. Used for querying for {@link TestApp} instances. */ 34 public final class TestAppProvider { 35 36 private static final String TAG = TestAppProvider.class.getSimpleName(); 37 38 // Must be instrumentation context to access resources 39 private static final Context sContext = TestApis.context().instrumentationContext(); 40 41 private boolean mTestAppsInitialised = false; 42 private final Set<TestAppDetails> mTestApps = new HashSet<>(); 43 44 /** Begin a query for a {@link TestApp}. */ query()45 public TestAppQueryBuilder query() { 46 return new TestAppQueryBuilder(this); 47 } 48 49 /** Get any {@link TestApp}. */ any()50 public TestApp any() { 51 TestApp testApp = query().get(); 52 Log.d(TAG, "any(): returning " + testApp); 53 return testApp; 54 } 55 testApps()56 Set<TestAppDetails> testApps() { 57 initTestApps(); 58 Log.d(TAG, "testApps(): returning " + mTestApps.size() + " apps (" + mTestApps + ")"); 59 return mTestApps; 60 } 61 initTestApps()62 private void initTestApps() { 63 if (mTestAppsInitialised) { 64 return; 65 } 66 mTestAppsInitialised = true; 67 68 int indexId = sContext.getResources().getIdentifier( 69 "raw/index", /* defType= */ null, sContext.getPackageName()); 70 71 try (InputStream inputStream = sContext.getResources().openRawResource(indexId)) { 72 TestappProtos.TestAppIndex index = TestappProtos.TestAppIndex.parseFrom(inputStream); 73 for (int i = 0; i < index.getAppsCount(); i++) { 74 loadApk(index.getApps(i)); 75 } 76 } catch (IOException e) { 77 throw new RuntimeException("Error loading testapp index", e); 78 } 79 } 80 loadApk(TestappProtos.AndroidApp app)81 private void loadApk(TestappProtos.AndroidApp app) { 82 TestAppDetails details = new TestAppDetails(); 83 details.mApp = app; 84 details.mResourceIdentifier = sContext.getResources().getIdentifier( 85 "raw/" + getApkNameWithoutSuffix(app.getApkName()), 86 /* defType= */ null, sContext.getPackageName()); 87 88 for (int i = 0; i < app.getMetadataCount(); i++) { 89 TestappProtos.Metadata metadataEntry = app.getMetadata(i); 90 details.mMetadata.putString(metadataEntry.getName(), metadataEntry.getValue()); 91 } 92 93 for (int i = 0; i < app.getPermissionsCount(); i++) { 94 details.mPermissions.add(app.getPermissions(i).getName()); 95 } 96 97 for (int i = 0; i < app.getActivitiesCount(); i++) { 98 TestappProtos.Activity activityEntry = app.getActivities(i); 99 details.mActivities.add(ActivityInfo.builder() 100 .activityClass(activityEntry.getName()) 101 .exported(activityEntry.getExported()) 102 .intentFilters(intentFilterSetFromProtoList( 103 activityEntry.getIntentFiltersList())) 104 .build()); 105 } 106 107 for (int i = 0; i < app.getServicesCount(); i++) { 108 TestappProtos.Service serviceEntry = app.getServices(i); 109 details.mServices.add(ServiceInfo.builder() 110 .serviceClass(serviceEntry.getName()) 111 .intentFilters(intentFilterSetFromProtoList( 112 serviceEntry.getIntentFiltersList())) 113 .build()); 114 } 115 116 mTestApps.add(details); 117 } 118 intentFilterSetFromProtoList( List<TestappProtos.IntentFilter> list)119 private Set<IntentFilter> intentFilterSetFromProtoList( 120 List<TestappProtos.IntentFilter> list) { 121 Set<IntentFilter> filterInfoSet = new HashSet<>(); 122 123 for (TestappProtos.IntentFilter filter : list) { 124 IntentFilter filterInfo = intentFilterFromProto(filter); 125 filterInfoSet.add(filterInfo); 126 } 127 128 return filterInfoSet; 129 } 130 intentFilterFromProto(TestappProtos.IntentFilter filterProto)131 private IntentFilter intentFilterFromProto(TestappProtos.IntentFilter filterProto) { 132 IntentFilter filter = new IntentFilter(); 133 134 for (String action : filterProto.getActionsList()) { 135 filter.addAction(action); 136 } 137 for (String category : filterProto.getCategoriesList()) { 138 filter.addCategory(category); 139 } 140 141 return filter; 142 } 143 getApkNameWithoutSuffix(String apkName)144 private String getApkNameWithoutSuffix(String apkName) { 145 return apkName.split("\\.", 2)[0]; 146 } 147 markTestAppUsed(TestAppDetails testApp)148 void markTestAppUsed(TestAppDetails testApp) { 149 mTestApps.remove(testApp); 150 } 151 } 152