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