• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.cts.verifier;
18 
19 import android.app.AlertDialog;
20 import android.app.Dialog;
21 import android.content.ContentResolver;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.DialogInterface.OnCancelListener;
26 import android.database.Cursor;
27 import android.os.Bundle;
28 import android.view.LayoutInflater;
29 import android.view.View;
30 import android.view.View.OnClickListener;
31 import android.widget.Button;
32 
33 /**
34  * {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
35  *
36  * <ol>
37  *     <li>Include the pass fail buttons layout in your layout:
38  *         <pre><include layout="@layout/pass_fail_buttons" /></pre>
39  *     </li>
40  *     <li>Extend one of the activities and call setPassFailButtonClickListeners after
41  *         setting your content view.</li>
42  *     <li>Make sure to call setResult(RESULT_CANCEL) in your Activity initially.</li>
43  *     <li>Optionally call setInfoTextResources to add an info button that will show a
44  *         dialog with instructional text.</li>
45  * </ol>
46  */
47 public class PassFailButtons {
48 
49     private static final int INFO_DIALOG_ID = 1337;
50 
51     private static final String INFO_DIALOG_VIEW_ID = "infoDialogViewId";
52     private static final String INFO_DIALOG_TITLE_ID = "infoDialogTitleId";
53     private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId";
54 
55     // Interface mostly for making documentation and refactoring easier...
56     private interface PassFailActivity {
57 
58         /**
59          * Hooks up the pass and fail buttons to click listeners that will record the test results.
60          * <p>
61          * Call from {@link Activity#onCreate} after {@link Activity #setContentView(int)}.
62          */
setPassFailButtonClickListeners()63         void setPassFailButtonClickListeners();
64 
65         /**
66          * Adds an initial informational dialog that appears when entering the test activity for
67          * the first time. Also enables the visibility of an "Info" button between the "Pass" and
68          * "Fail" buttons that can be clicked to show the information dialog again.
69          * <p>
70          * Call from {@link Activity#onCreate} after {@link Activity #setContentView(int)}.
71          *
72          * @param titleId for the text shown in the dialog title area
73          * @param messageId for the text shown in the dialog's body area
74          */
setInfoResources(int titleId, int messageId, int viewId)75         void setInfoResources(int titleId, int messageId, int viewId);
76 
getPassButton()77         Button getPassButton();
78 
79         /**
80          * Returns a unique identifier for the test.  Usually, this is just the class name.
81          */
getTestId()82         String getTestId();
83 
84         /** @return null or details about the test run. */
getTestDetails()85         String getTestDetails();
86     }
87 
88     public static class Activity extends android.app.Activity implements PassFailActivity {
89 
90         @Override
setPassFailButtonClickListeners()91         public void setPassFailButtonClickListeners() {
92             setPassFailClickListeners(this);
93         }
94 
95         @Override
setInfoResources(int titleId, int messageId, int viewId)96         public void setInfoResources(int titleId, int messageId, int viewId) {
97             setInfo(this, titleId, messageId, viewId);
98         }
99 
100         @Override
getPassButton()101         public Button getPassButton() {
102             return getPassButtonView(this);
103         }
104 
105         @Override
onCreateDialog(int id, Bundle args)106         public Dialog onCreateDialog(int id, Bundle args) {
107             return createDialog(this, id, args);
108         }
109 
110         @Override
getTestId()111         public String getTestId() {
112             return getClass().getName();
113         }
114 
115         @Override
getTestDetails()116         public String getTestDetails() {
117             return null;
118         }
119     }
120 
121     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
122 
123         @Override
setPassFailButtonClickListeners()124         public void setPassFailButtonClickListeners() {
125             setPassFailClickListeners(this);
126         }
127 
128         @Override
setInfoResources(int titleId, int messageId, int viewId)129         public void setInfoResources(int titleId, int messageId, int viewId) {
130             setInfo(this, titleId, messageId, viewId);
131         }
132 
133         @Override
getPassButton()134         public Button getPassButton() {
135             return getPassButtonView(this);
136         }
137 
138         @Override
onCreateDialog(int id, Bundle args)139         public Dialog onCreateDialog(int id, Bundle args) {
140             return createDialog(this, id, args);
141         }
142 
143         @Override
getTestId()144         public String getTestId() {
145             return getClass().getName();
146         }
147 
148         @Override
getTestDetails()149         public String getTestDetails() {
150             return null;
151         }
152     }
153 
154     public static class TestListActivity extends AbstractTestListActivity
155             implements PassFailActivity {
156 
157         @Override
setPassFailButtonClickListeners()158         public void setPassFailButtonClickListeners() {
159             setPassFailClickListeners(this);
160         }
161 
162         @Override
setInfoResources(int titleId, int messageId, int viewId)163         public void setInfoResources(int titleId, int messageId, int viewId) {
164             setInfo(this, titleId, messageId, viewId);
165         }
166 
167         @Override
getPassButton()168         public Button getPassButton() {
169             return getPassButtonView(this);
170         }
171 
172         @Override
onCreateDialog(int id, Bundle args)173         public Dialog onCreateDialog(int id, Bundle args) {
174             return createDialog(this, id, args);
175         }
176 
177         @Override
getTestId()178         public String getTestId() {
179             return getClass().getName();
180         }
181 
182         @Override
getTestDetails()183         public String getTestDetails() {
184             return null;
185         }
186     }
187 
188     private static <T extends android.app.Activity & PassFailActivity>
setPassFailClickListeners(final T activity)189             void setPassFailClickListeners(final T activity) {
190         View.OnClickListener clickListener = new View.OnClickListener() {
191             @Override
192             public void onClick(View target) {
193                 setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
194                         target);
195             }
196         };
197 
198         activity.findViewById(R.id.pass_button).setOnClickListener(clickListener);
199         activity.findViewById(R.id.fail_button).setOnClickListener(clickListener);
200     }
201 
setInfo(final android.app.Activity activity, final int titleId, final int messageId, final int viewId)202     private static void setInfo(final android.app.Activity activity, final int titleId,
203             final int messageId, final int viewId) {
204         // Show the middle "info" button and make it show the info dialog when clicked.
205         View infoButton = activity.findViewById(R.id.info_button);
206         infoButton.setVisibility(View.VISIBLE);
207         infoButton.setOnClickListener(new OnClickListener() {
208             @Override
209             public void onClick(View view) {
210                 showInfoDialog(activity, titleId, messageId, viewId);
211             }
212         });
213 
214         // Show the info dialog if the user has never seen it before.
215         if (!hasSeenInfoDialog(activity)) {
216             showInfoDialog(activity, titleId, messageId, viewId);
217         }
218     }
219 
hasSeenInfoDialog(android.app.Activity activity)220     private static boolean hasSeenInfoDialog(android.app.Activity activity) {
221         ContentResolver resolver = activity.getContentResolver();
222         Cursor cursor = null;
223         try {
224             cursor = resolver.query(
225                     TestResultsProvider.getTestNameUri(activity.getClass().getName()),
226                     new String[] {TestResultsProvider.COLUMN_TEST_INFO_SEEN}, null, null, null);
227             return cursor.moveToFirst() && cursor.getInt(0) > 0;
228         } finally {
229             if (cursor != null) {
230                 cursor.close();
231             }
232         }
233     }
234 
showInfoDialog(final android.app.Activity activity, int titleId, int messageId, int viewId)235     private static void showInfoDialog(final android.app.Activity activity, int titleId,
236             int messageId, int viewId) {
237         Bundle args = new Bundle();
238         args.putInt(INFO_DIALOG_TITLE_ID, titleId);
239         args.putInt(INFO_DIALOG_MESSAGE_ID, messageId);
240         args.putInt(INFO_DIALOG_VIEW_ID, viewId);
241         activity.showDialog(INFO_DIALOG_ID, args);
242     }
243 
createDialog(final android.app.Activity activity, int id, Bundle args)244     private static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
245         switch (id) {
246             case INFO_DIALOG_ID:
247                 return createInfoDialog(activity, id, args);
248             default:
249                 throw new IllegalArgumentException("Bad dialog id: " + id);
250         }
251     }
252 
createInfoDialog(final android.app.Activity activity, int id, Bundle args)253     private static Dialog createInfoDialog(final android.app.Activity activity, int id,
254             Bundle args) {
255         int viewId = args.getInt(INFO_DIALOG_VIEW_ID);
256         int titleId = args.getInt(INFO_DIALOG_TITLE_ID);
257         int messageId = args.getInt(INFO_DIALOG_MESSAGE_ID);
258 
259         AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(
260                 android.R.drawable.ic_dialog_info).setTitle(titleId);
261         if (viewId > 0) {
262             LayoutInflater inflater = (LayoutInflater) activity
263                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
264             builder.setView(inflater.inflate(viewId, null));
265         } else {
266             builder.setMessage(messageId);
267         }
268         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
269             @Override
270             public void onClick(DialogInterface dialog, int which) {
271                 markSeenInfoDialog(activity);
272             }
273         }).setOnCancelListener(new OnCancelListener() {
274             @Override
275             public void onCancel(DialogInterface dialog) {
276                 markSeenInfoDialog(activity);
277             }
278         });
279         return builder.create();
280     }
281 
markSeenInfoDialog(android.app.Activity activity)282     private static void markSeenInfoDialog(android.app.Activity activity) {
283         ContentResolver resolver = activity.getContentResolver();
284         ContentValues values = new ContentValues(2);
285         values.put(TestResultsProvider.COLUMN_TEST_NAME, activity.getClass().getName());
286         values.put(TestResultsProvider.COLUMN_TEST_INFO_SEEN, 1);
287         int numUpdated = resolver.update(
288                 TestResultsProvider.getTestNameUri(activity.getClass().getName()),
289                 values, null, null);
290         if (numUpdated == 0) {
291             resolver.insert(TestResultsProvider.RESULTS_CONTENT_URI, values);
292         }
293     }
294 
295     /** Set the test result corresponding to the button clicked and finish the activity. */
setTestResultAndFinish(android.app.Activity activity, String testId, String testDetails, View target)296     private static void setTestResultAndFinish(android.app.Activity activity, String testId,
297             String testDetails, View target) {
298         boolean passed;
299         switch (target.getId()) {
300             case R.id.pass_button:
301                 passed = true;
302                 break;
303             case R.id.fail_button:
304                 passed = false;
305                 break;
306             default:
307                 throw new IllegalArgumentException("Unknown id: " + target.getId());
308         }
309         setTestResultAndFinish(activity, testId, testDetails, passed);
310     }
311 
312     /** Set the test result and finish the activity. */
setTestResultAndFinish(android.app.Activity activity, String testId, String testDetails, boolean passed)313     public static void setTestResultAndFinish(android.app.Activity activity, String testId,
314             String testDetails, boolean passed) {
315         if (passed) {
316             TestResult.setPassedResult(activity, testId, testDetails);
317         } else {
318             TestResult.setFailedResult(activity, testId, testDetails);
319         }
320 
321         activity.finish();
322     }
323 
getPassButtonView(android.app.Activity activity)324     private static Button getPassButtonView(android.app.Activity activity) {
325         return (Button) activity.findViewById(R.id.pass_button);
326     }
327 }
328