1 // Copyright 2013 Google Inc. All Rights Reserved.
2 
3 package com.android.cts.verifier;
4 
5 import android.content.Intent;
6 import android.os.Bundle;
7 import android.os.Parcel;
8 import android.os.Parcelable;
9 import android.view.View;
10 import android.view.View.OnClickListener;
11 import android.view.ViewGroup;
12 import android.widget.Button;
13 import android.widget.TextView;
14 
15 /**
16  *  A generic activity for intent based tests.
17  *
18  *  This activity can be reused for various tests that are intent based. The activity consists of a
19  *  text view containing instructions and one or more buttons that trigger intents.
20  *  Each button can send one or more intenrs as startActivity() calls.
21  *
22  *  The intents can either be generated statically and passed as an extra to the intent that started
23  *  this activity or in some cases where the intent needs to be based on dynamic data (for example
24  *  time of day), an {@link IntentFactory} class name can be passed instead. This intent factory
25  *  will dynamically create the intent when the button is clicked based on the test id and the
26  *  button that was clicked.
27  */
28 public class IntentDrivenTestActivity extends PassFailButtons.Activity implements OnClickListener {
29     public static final String EXTRA_ID = "id";
30     public static final String EXTRA_TITLE = "title";
31     public static final String EXTRA_INFO = "info";
32     public static final String EXTRA_BUTTONS = "buttons";
33 
34     private String mTestId;
35     private ButtonInfo[] mButtonInfos;
36 
37 
38     @Override
onCreate(Bundle savedInstanceState)39     protected void onCreate(Bundle savedInstanceState) {
40         super.onCreate(savedInstanceState);
41         setContentView(R.layout.intent_driven_test);
42         setPassFailButtonClickListeners();
43 
44         final Intent intent = getIntent();
45         if (!intent.hasExtra(EXTRA_ID)
46                 || !intent.hasExtra(EXTRA_TITLE)
47                 || !intent.hasExtra(EXTRA_INFO)
48                 || !intent.hasExtra(EXTRA_BUTTONS)) {
49             throw new IllegalArgumentException(
50                     "Intent must have EXTRA_ID, EXTRA_TITLE, EXTRA_INFO & EXTRA_BUTTONS");
51         }
52 
53         mTestId = intent.getStringExtra(EXTRA_ID);
54         setTitle(intent.getIntExtra(EXTRA_TITLE, -1));
55 
56         final TextView info = (TextView) findViewById(R.id.info);
57         info.setText(intent.getIntExtra(EXTRA_INFO, -1));
58 
59         final ViewGroup buttons = (ViewGroup) findViewById(R.id.buttons);
60         final Parcelable[] parcelables = intent.getParcelableArrayExtra(EXTRA_BUTTONS);
61         mButtonInfos = new ButtonInfo[parcelables.length];
62         for (int i = 0; i < parcelables.length; i++) {
63             final ButtonInfo buttonInfo = (ButtonInfo) parcelables[i];
64             mButtonInfos[i] = buttonInfo;
65             final Button button = new Button(this);
66             buttons.addView(button);
67             button.setText(buttonInfo.mButtonText);
68             button.setTag(i);
69             button.setOnClickListener(this);
70         }
71     }
72 
73     @Override
onResume()74     protected void onResume() {
75         super.onResume();
76         setResult(RESULT_CANCELED);
77     }
78 
79     @Override
onClick(View v)80     public void onClick(View v) {
81         final ButtonInfo buttonInfo = mButtonInfos[(Integer) v.getTag()];
82         final Intent[] intents = buttonInfo.getIntents();
83         if (intents != null) {
84             for (Parcelable intent : intents) {
85                 startActivity((Intent) intent);
86             }
87         } else {
88             final Class<?> factoryClass;
89             final String className = buttonInfo.getIntentFactoryClassName();
90             try {
91                 factoryClass = Thread.currentThread().getContextClassLoader().loadClass(className);
92             } catch (ClassNotFoundException e) {
93                 throw new IllegalArgumentException("Factory not found: " + className, e);
94             }
95             final IntentFactory factory;
96             try {
97                 factory = (IntentFactory) factoryClass.newInstance();
98             } catch (InstantiationException e) {
99                 throw new IllegalArgumentException("Can't create factory: " + className, e);
100             } catch (IllegalAccessException e) {
101                 throw new IllegalArgumentException("Can't create factory: " + className, e);
102             }
103 
104             for (Intent intent : factory.createIntents(mTestId, buttonInfo.getButtonText())) {
105                 startActivity(intent);
106             }
107         }
108     }
109 
110     @Override
getTestId()111     public String getTestId() {
112         return mTestId;
113     }
114 
115     public static class TestInfo {
116         private final String mTestId;
117         private final int mTitle;
118         private final int mInfoText;
119         private final ButtonInfo[] mButtons;
120 
TestInfo(String testId, int title, int infoText, ButtonInfo... buttons)121         public TestInfo(String testId,  int title, int infoText, ButtonInfo... buttons) {
122             /** The Intent Driven Test layout {@link R.layout.intent_driven_test} is designed for
123              *  up to 2 buttons and won't render well with more buttons on small screen devices.
124              *  If you need more than 2 buttons, please change the layout so it can properly render
125              *  them even on the smallest devices.
126              */
127             if (buttons.length > 2) {
128                 throw new RuntimeException("Too many buttons");
129             }
130             mTestId = testId;
131             mTitle = title;
132             mInfoText = infoText;
133             mButtons = buttons;
134         }
135 
getTestId()136         public String getTestId() {
137             return mTestId;
138         }
139 
getTitle()140         public int getTitle() {
141             return mTitle;
142         }
143 
getInfoText()144         public int getInfoText() {
145             return mInfoText;
146         }
147 
getButtons()148         public ButtonInfo[] getButtons() {
149             return mButtons;
150         }
151     }
152 
153     public static class ButtonInfo implements Parcelable {
154         private final int mButtonText;
155         private final Intent[] mIntents;
156         private final String mIntentFactoryClassName;
157 
ButtonInfo(int buttonText, Intent... intents)158         public ButtonInfo(int buttonText, Intent... intents) {
159             mButtonText = buttonText;
160             mIntents = intents;
161             mIntentFactoryClassName = null;
162         }
163 
ButtonInfo(int buttonText, String intentFactoryClassName)164         public ButtonInfo(int buttonText, String intentFactoryClassName) {
165             mButtonText = buttonText;
166             mIntents = null;
167             mIntentFactoryClassName = intentFactoryClassName;
168         }
169 
ButtonInfo(Parcel source)170         public ButtonInfo(Parcel source) {
171             mButtonText = source.readInt();
172             final Parcelable[] parcelables = source.readParcelableArray(null);
173             if (parcelables != null) {
174                 mIntents = new Intent[parcelables.length];
175                 for (int i = 0, parcelablesLength = parcelables.length; i < parcelablesLength; i++) {
176                     mIntents[i] = (Intent) parcelables[i];
177                 }
178             } else {
179                 mIntents = null;
180             }
181             mIntentFactoryClassName = source.readString();
182         }
183 
getButtonText()184         public int getButtonText() {
185             return mButtonText;
186         }
187 
getIntents()188         public Intent[] getIntents() {
189             return mIntents;
190         }
191 
getIntentFactoryClassName()192         public String getIntentFactoryClassName() {
193             return mIntentFactoryClassName;
194         }
195 
196         @Override
describeContents()197         public int describeContents() {
198             return 0;
199         }
200 
201         @Override
writeToParcel(Parcel dest, int flags)202         public void writeToParcel(Parcel dest, int flags) {
203             dest.writeInt(mButtonText);
204             dest.writeParcelableArray(mIntents, 0);
205             dest.writeString(mIntentFactoryClassName);
206         }
207 
208         public static final Creator<ButtonInfo> CREATOR = new Creator<ButtonInfo>() {
209             public ButtonInfo createFromParcel(Parcel source) {
210                 return new ButtonInfo(source);
211             }
212 
213             public ButtonInfo[] newArray(int size) {
214                 return new ButtonInfo[size];
215             }
216         };
217 
218     }
219 
220     public interface IntentFactory {
createIntents(String testId, int buttonText)221         Intent[] createIntents(String testId, int buttonText);
222     }
223 }
224