• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.compatibility.common.util.FileUtils.readInputStreamFully;
20 
21 import android.content.Context;
22 import android.os.Bundle;
23 import android.os.UserHandle;
24 
25 import androidx.annotation.Nullable;
26 
27 import com.android.bedstead.nene.TestApis;
28 import com.android.bedstead.nene.exceptions.NeneException;
29 import com.android.bedstead.nene.packages.Package;
30 import com.android.bedstead.nene.users.UserReference;
31 import com.android.bedstead.nene.users.Users;
32 import com.android.bedstead.testapp.processor.annotations.TestAppSender;
33 import com.android.queryable.collections.QueryableActivityInfoHashSet;
34 
35 import java.io.File;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.util.Objects;
40 import java.util.Set;
41 
42 /** Represents a single test app which can be installed and interacted with. */
43 @TestAppSender
44 public final class TestApp {
45     // Must be instrumentation context to access resources
46     private static final Context sContext = TestApis.context().instrumentationContext();
47     private static final String LOG_TAG = "TestApp";
48     final TestAppDetails mDetails;
49 
TestApp(TestAppDetails details)50     TestApp(TestAppDetails details) {
51         if (details == null) {
52             throw new NullPointerException();
53         }
54         mDetails = details;
55     }
56 
57     /**
58      * Get a {@link Package} for the {@link TestApp}.
59      *
60      * <p>This will only be resolvable after the app is installed.
61      */
pkg()62     public Package pkg() {
63         return TestApis.packages().find(packageName());
64     }
65 
66     /**
67      * Install the {@link TestApp} on the device for the instrumented user.
68      *
69      * <p>See {@link Users#instrumented()}
70      */
install()71     public TestAppInstance install() {
72         return install(TestApis.users().instrumented());
73     }
74 
75     /**
76      * Install the {@link TestApp} on the device for the given {@link UserReference}.
77      */
install(UserReference user)78     public TestAppInstance install(UserReference user) {
79         try {
80             pkg().installBytes(user, this::apkBytes);
81 //            pkg().setAllowTestApiAccess(true);
82         } catch (NeneException e) {
83             throw new NeneException("Error while installing TestApp " + this, e);
84         }
85 
86         return new TestAppInstance(this, user);
87     }
88 
89     /**
90      * Install the {@link TestApp} on the device for the given {@link UserHandle}.
91      */
install(UserHandle user)92     public TestAppInstance install(UserHandle user) {
93         install(TestApis.users().find(user));
94         return instance(user);
95     }
96 
97     /**
98      * Uninstall the {@link TestApp} on the device from the instrumented user.
99      *
100      * <p>See {@link Users#instrumented()}
101      */
uninstall()102     public void uninstall() {
103         uninstall(TestApis.users().instrumented());
104     }
105 
106     /**
107      * Check if {@link TestApp} is installed on the given {@link UserReference}
108      */
installedOnUser(UserReference user)109     public boolean installedOnUser(UserReference user) {
110         return pkg().installedOnUser(user);
111     }
112 
113     /**
114      * Check if {@link TestApp} is installed on the given {@link UserHandle}
115      */
installedOnUser(UserHandle user)116     public boolean installedOnUser(UserHandle user) {
117         return pkg().installedOnUser(user);
118     }
119 
120     /**
121      * Uninstall the {@link TestApp} from the device from all users.
122      */
uninstallFromAllUsers()123     public void uninstallFromAllUsers() {
124         pkg().uninstallFromAllUsers();
125     }
126 
127     /**
128      * Uninstall the {@link TestApp} on the device from the given {@link UserReference}.
129      */
uninstall(UserReference user)130     public void uninstall(UserReference user) {
131         pkg().uninstall(user);
132     }
133 
134     /**
135      * Uninstall the {@link TestApp} on the device from the given {@link UserHandle}.
136      */
uninstall(UserHandle user)137     public void uninstall(UserHandle user) {
138         uninstall(TestApis.users().find(user));
139     }
140 
141     /**
142      * Get a reference to the specific instance of this test app on a given user.
143      *
144      * <p>This does not check if the user exists, or if the test app is installed on the user.
145      */
instance(UserHandle user)146     public TestAppInstance instance(UserHandle user) {
147         return instance(TestApis.users().find(user));
148     }
149 
150     /**
151      * Get a reference to the specific instance of this test app on a given user.
152      *
153      * <p>This does not check if the user exists, or if the test app is installed on the user.
154      */
instance(UserReference user)155     public TestAppInstance instance(UserReference user) {
156         if (user == null) {
157             throw new NullPointerException();
158         }
159         return new TestAppInstance(this, user);
160     }
161 
162     /**
163      * Returns an {@link InputStream} of the apk for this app.
164      */
apkStream()165     public InputStream apkStream() {
166         return sContext.getResources().openRawResource(mDetails.mResourceIdentifier);
167     }
168 
169     /**
170      * Returns a byte array of the apk for this app.
171      */
apkBytes()172     public byte[] apkBytes() {
173         try (InputStream inputStream = apkStream()) {
174             return readInputStreamFully(inputStream);
175         } catch (IOException e) {
176             throw new NeneException("Error when reading TestApp bytes", e);
177         }
178     }
179 
180     /** Write the APK file to the given {@link File}. */
writeApkFile(File outputFile)181     public void writeApkFile(File outputFile) throws IOException {
182         outputFile.getParentFile().mkdirs();
183         try (FileOutputStream output = new FileOutputStream(outputFile)) {
184             output.write(apkBytes());
185         }
186     }
187 
188     /** The package label, or the package name if no label is specified. */
label()189     public String label() {
190         return mDetails.label() != null ? mDetails.label() : packageName();
191     }
192 
193     /** The package name of the test app. */
packageName()194     public String packageName() {
195         return mDetails.mApp.getPackageName();
196     }
197 
198     /** The testOnly attribute for the test app. */
testOnly()199     public boolean testOnly() {
200         return mDetails.mApp.getTestOnly();
201     }
202 
203     /** The minSdkVersion of the test app. */
minSdkVersion()204     public int minSdkVersion() {
205         return mDetails.mApp.getUsesSdk().getMinSdkVersion();
206     }
207 
208     /** The maxSdkVersion of the test app. */
maxSdkVersion()209     public int maxSdkVersion() {
210         return mDetails.mApp.getUsesSdk().getMaxSdkVersion();
211     }
212 
213     /** The targetSdkVersion of the test app. */
targetSdkVersion()214     public int targetSdkVersion() {
215         return mDetails.mApp.getUsesSdk().getTargetSdkVersion();
216     }
217 
218     /** The permissions declared by the test app. */
permissions()219     public Set<String> permissions() {
220         return mDetails.mPermissions;
221     }
222 
223     /** The activities which exist in the test app. */
activities()224     public QueryableActivityInfoHashSet activities() {
225         return new QueryableActivityInfoHashSet(mDetails.mActivities);
226     }
227 
228     /**
229      * The metadata declared by the test app.
230      *
231      * <p>Note that currently all values are of type String.
232      */
metadata()233     public Bundle metadata() {
234         return mDetails.mMetadata;
235     }
236 
237     @Override
toString()238     public String toString() {
239         return "TestApp{"
240                 + "packageName=" + packageName()
241                 + "}";
242     }
243 
244     /** The shared user id of the test app, if any. */
245     @Nullable
sharedUserId()246     public String sharedUserId() {
247         return mDetails.sharedUserId();
248     }
249 
250     @Override
equals(Object o)251     public boolean equals(Object o) {
252         if (this == o) return true;
253         if (!(o instanceof TestApp)) return false;
254         TestApp testApp = (TestApp) o;
255         return mDetails.mApp.getPackageName().equals(testApp.mDetails.mApp.getPackageName());
256     }
257 
258     @Override
hashCode()259     public int hashCode() {
260         return Objects.hash(mDetails.mApp.getPackageName());
261     }
262 }
263