Home | History | Annotate | Download | only in verifier
      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          */
     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          */
     75         void setInfoResources(int titleId, int messageId, int viewId);
     76 
     77         Button getPassButton();
     78 
     79         /**
     80          * Returns a unique identifier for the test.  Usually, this is just the class name.
     81          */
     82         String getTestId();
     83 
     84         /** @return null or details about the test run. */
     85         String getTestDetails();
     86     }
     87 
     88     public static class Activity extends android.app.Activity implements PassFailActivity {
     89 
     90         @Override
     91         public void setPassFailButtonClickListeners() {
     92             setPassFailClickListeners(this);
     93         }
     94 
     95         @Override
     96         public void setInfoResources(int titleId, int messageId, int viewId) {
     97             setInfo(this, titleId, messageId, viewId);
     98         }
     99 
    100         @Override
    101         public Button getPassButton() {
    102             return getPassButtonView(this);
    103         }
    104 
    105         @Override
    106         public Dialog onCreateDialog(int id, Bundle args) {
    107             return createDialog(this, id, args);
    108         }
    109 
    110         @Override
    111         public String getTestId() {
    112             return getClass().getName();
    113         }
    114 
    115         @Override
    116         public String getTestDetails() {
    117             return null;
    118         }
    119     }
    120 
    121     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
    122 
    123         @Override
    124         public void setPassFailButtonClickListeners() {
    125             setPassFailClickListeners(this);
    126         }
    127 
    128         @Override
    129         public void setInfoResources(int titleId, int messageId, int viewId) {
    130             setInfo(this, titleId, messageId, viewId);
    131         }
    132 
    133         @Override
    134         public Button getPassButton() {
    135             return getPassButtonView(this);
    136         }
    137 
    138         @Override
    139         public Dialog onCreateDialog(int id, Bundle args) {
    140             return createDialog(this, id, args);
    141         }
    142 
    143         @Override
    144         public String getTestId() {
    145             return getClass().getName();
    146         }
    147 
    148         @Override
    149         public String getTestDetails() {
    150             return null;
    151         }
    152     }
    153 
    154     public static class TestListActivity extends AbstractTestListActivity
    155             implements PassFailActivity {
    156 
    157         @Override
    158         public void setPassFailButtonClickListeners() {
    159             setPassFailClickListeners(this);
    160         }
    161 
    162         @Override
    163         public void setInfoResources(int titleId, int messageId, int viewId) {
    164             setInfo(this, titleId, messageId, viewId);
    165         }
    166 
    167         @Override
    168         public Button getPassButton() {
    169             return getPassButtonView(this);
    170         }
    171 
    172         @Override
    173         public Dialog onCreateDialog(int id, Bundle args) {
    174             return createDialog(this, id, args);
    175         }
    176 
    177         @Override
    178         public String getTestId() {
    179             return getClass().getName();
    180         }
    181 
    182         @Override
    183         public String getTestDetails() {
    184             return null;
    185         }
    186     }
    187 
    188     private static <T extends android.app.Activity & PassFailActivity>
    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 
    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 
    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 
    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 
    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 
    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 
    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. */
    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. */
    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 
    324     private static Button getPassButtonView(android.app.Activity activity) {
    325         return (Button) activity.findViewById(R.id.pass_button);
    326     }
    327 }
    328