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