1 /*
2  * Copyright (C) 2014 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 android.support.test.aupt;
18 
19 import android.app.Instrumentation;
20 import android.support.test.uiautomator.By;
21 import android.support.test.uiautomator.UiDevice;
22 import android.support.test.uiautomator.UiObject2;
23 import android.support.test.uiautomator.UiWatcher;
24 import android.support.test.uiautomator.Until;
25 import android.util.Log;
26 
27 import java.util.ArrayList;
28 import java.util.Collections;
29 import java.util.List;
30 
31 public class UiWatchers {
32     private static final String LOG_TAG = UiWatchers.class.getSimpleName();
33     private final List<String> mErrors = new ArrayList<String>();
34 
35     /**
36      * We can use the UiDevice registerWatcher to register a small script to be executed when the
37      * framework is waiting for a control to appear. Waiting may be the cause of an unexpected
38      * dialog on the screen and it is the time when the framework runs the registered watchers.
39      * This is a sample watcher looking for ANR and crashes. it closes it and moves on. You should
40      * create your own watchers and handle error logging properly for your type of tests.
41      */
registerAnrAndCrashWatchers(Instrumentation instr)42     public void registerAnrAndCrashWatchers(Instrumentation instr) {
43         final UiDevice device = UiDevice.getInstance(instr);
44 
45         // class names may have changed
46         device.registerWatcher("AnrWatcher", new UiWatcher() {
47             @Override
48             public boolean checkForCondition() {
49                 UiObject2 window = device.findObject(
50                         By.pkg("android").textContains("isn't responding"));
51                 if (window != null) {
52                     String errorText = window.getText();
53                     onAnrDetected(errorText);
54                     postHandler(device);
55                     return true; // triggered
56                 }
57                 return false; // no trigger
58             }
59         });
60 
61         device.registerWatcher("CrashWatcher", new UiWatcher() {
62             @Override
63             public boolean checkForCondition() {
64                 UiObject2 window = device.findObject(
65                         By.pkg("android").textContains("has stopped"));
66                 if (window != null) {
67                     String errorText = window.getText();
68                     onCrashDetected(errorText);
69                     postHandler(device);
70                     return true; // triggered
71                 }
72                 return false; // no trigger
73             }
74         });
75 
76         Log.i(LOG_TAG, "Registed GUI Exception watchers");
77     }
78 
removeAnrAndCrashWatchers(Instrumentation instr)79     public void removeAnrAndCrashWatchers(Instrumentation instr) {
80         final UiDevice device = UiDevice.getInstance(instr);
81         device.removeWatcher("AnrWatcher");
82         device.removeWatcher("CrashWatcher");
83     }
84 
onAnrDetected(String errorText)85     public void onAnrDetected(String errorText) {
86         mErrors.add(errorText);
87     }
88 
onCrashDetected(String errorText)89     public void onCrashDetected(String errorText) {
90         mErrors.add(errorText);
91     }
92 
reset()93     public void reset() {
94         mErrors.clear();
95     }
96 
getErrors()97     public List<String> getErrors() {
98         return Collections.unmodifiableList(mErrors);
99     }
100 
101     /**
102      * Current implementation ignores the exception and continues.
103      */
postHandler(UiDevice device)104     public void postHandler(UiDevice device) {
105         // TODO: Add custom error logging here
106 
107         String formatedOutput = String.format("UI Exception Message: %-20s\n",
108                 device.getCurrentPackageName());
109         Log.e(LOG_TAG, formatedOutput);
110 
111         UiObject2 buttonMute = device.findObject(By.res("android", "aerr_mute"));
112         if (buttonMute != null) {
113             buttonMute.click();
114         }
115 
116         UiObject2 closeAppButton = device.findObject(By.res("android", "aerr_close"));
117         if (closeAppButton != null) {
118             closeAppButton.click();
119         }
120 
121         // sometimes it takes a while for the OK button to become enabled
122         UiObject2 buttonOK = device.findObject(By.text("OK").enabled(true));
123         if (buttonOK != null) {
124             buttonOK.click();
125         }
126     }
127 }
128