1 /*
2  * Copyright (C) 2015 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 package com.android.compatibility.common.deviceinfo;
17 
18 import android.app.Activity;
19 import android.app.Instrumentation;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ActivityInfo;
23 import android.content.pm.PackageManager;
24 import android.os.Bundle;
25 import android.text.TextUtils;
26 import android.util.Log;
27 
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.Set;
31 
32 /**
33  * An instrumentation that runs all activities that extends DeviceInfoActivity.
34  */
35 public class DeviceInfoInstrument extends Instrumentation {
36 
37     private static final String LOG_TAG = "ExtendedDeviceInfo";
38     private static final String COLLECTOR = "collector";
39 
40     // List of collectors to run. If null or empty, all collectors will run.
41     private Set<String> mCollectorSet = new HashSet<String>();
42 
43     // Results sent to the caller when this istrumentation completes.
44     private Bundle mBundle = new Bundle();
45 
46     @Override
onCreate(Bundle savedInstanceState)47     public void onCreate(Bundle savedInstanceState) {
48         super.onCreate(savedInstanceState);
49         if (savedInstanceState != null) {
50             String collectorList = savedInstanceState.getString(COLLECTOR);
51             if (!TextUtils.isEmpty(collectorList)) {
52                 for (String collector : TextUtils.split(collectorList, ",")) {
53                   if (!TextUtils.isEmpty(collector)) {
54                     mCollectorSet.add(collector);
55                   }
56                 }
57             }
58         }
59         start();
60     }
61 
62     @Override
onStart()63     public void onStart() {
64         try {
65             Context context = getContext();
66             ActivityInfo[] activities = context.getPackageManager().getPackageInfo(
67                     context.getPackageName(), PackageManager.GET_ACTIVITIES).activities;
68             for (ActivityInfo activityInfo : activities) {
69                 runActivity(activityInfo.name);
70             }
71         } catch (Exception e) {
72             Log.e(LOG_TAG, "Exception occurred while running activities.", e);
73             // Returns INSTRUMENTATION_CODE: 0
74             finish(Activity.RESULT_CANCELED, mBundle);
75         }
76         // Returns INSTRUMENTATION_CODE: -1
77         finish(Activity.RESULT_OK, mBundle);
78     }
79 
80     /**
81      * Returns true if the activity meets the criteria to run; otherwise, false.
82      */
isActivityRunnable(Class activityClass)83     private boolean isActivityRunnable(Class activityClass) {
84         // Don't run the base DeviceInfoActivity class.
85         if (DeviceInfoActivity.class == activityClass) {
86             return false;
87         }
88         // Don't run anything that doesn't extends DeviceInfoActivity.
89         if (!DeviceInfoActivity.class.isAssignableFrom(activityClass)) {
90             return false;
91         }
92         // Only run activity if mCollectorSet is empty or contains it.
93         if (mCollectorSet != null && mCollectorSet.size() > 0) {
94             return mCollectorSet.contains(activityClass.getName());
95         }
96         // Run anything that makes it here.
97         return true;
98     }
99 
100     /**
101      * Runs a device info activity and return the file path where the results are written to.
102      */
runActivity(String activityName)103     private void runActivity(String activityName) throws Exception {
104         Class activityClass = null;
105         try {
106             activityClass = Class.forName(activityName);
107         } catch (ClassNotFoundException e) {
108             return;
109         }
110 
111         if (activityClass == null || !isActivityRunnable(activityClass)) {
112             return;
113         }
114 
115         Intent intent = new Intent();
116         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
117         intent.setClassName(this.getContext(), activityName);
118 
119         DeviceInfoActivity activity = (DeviceInfoActivity) startActivitySync(intent);
120         waitForIdleSync();
121         activity.waitForActivityToFinish();
122 
123         String className = activityClass.getSimpleName();
124         String errorMessage = activity.getErrorMessage();
125         if (TextUtils.isEmpty(errorMessage)) {
126             mBundle.putString(className, activity.getResultFilePath());
127         } else {
128             mBundle.putString(className, errorMessage);
129             throw new Exception(errorMessage);
130         }
131     }
132 }
133 
134