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 com.android.compatibility.common.util.ReportLog;
     20 
     21 import android.app.AlertDialog;
     22 import android.app.Dialog;
     23 import android.content.ContentResolver;
     24 import android.content.ContentValues;
     25 import android.content.Context;
     26 import android.content.DialogInterface;
     27 import android.content.DialogInterface.OnCancelListener;
     28 import android.content.pm.PackageManager;
     29 import android.database.Cursor;
     30 import android.os.Bundle;
     31 import android.os.PowerManager;
     32 import android.os.PowerManager.WakeLock;
     33 import android.view.LayoutInflater;
     34 import android.view.View;
     35 import android.view.View.OnClickListener;
     36 import android.widget.ImageButton;
     37 import android.widget.Toast;
     38 
     39 /**
     40  * {@link Activity}s to handle clicks to the pass and fail buttons of the pass fail buttons layout.
     41  *
     42  * <ol>
     43  *     <li>Include the pass fail buttons layout in your layout:
     44  *         <pre><include layout="@layout/pass_fail_buttons" /></pre>
     45  *     </li>
     46  *     <li>Extend one of the activities and call setPassFailButtonClickListeners after
     47  *         setting your content view.</li>
     48  *     <li>Make sure to call setResult(RESULT_CANCEL) in your Activity initially.</li>
     49  *     <li>Optionally call setInfoTextResources to add an info button that will show a
     50  *         dialog with instructional text.</li>
     51  * </ol>
     52  */
     53 public class PassFailButtons {
     54 
     55     private static final int INFO_DIALOG_ID = 1337;
     56 
     57     private static final String INFO_DIALOG_VIEW_ID = "infoDialogViewId";
     58     private static final String INFO_DIALOG_TITLE_ID = "infoDialogTitleId";
     59     private static final String INFO_DIALOG_MESSAGE_ID = "infoDialogMessageId";
     60 
     61     // Interface mostly for making documentation and refactoring easier...
     62     public interface PassFailActivity {
     63 
     64         /**
     65          * Hooks up the pass and fail buttons to click listeners that will record the test results.
     66          * <p>
     67          * Call from {@link Activity#onCreate} after {@link Activity #setContentView(int)}.
     68          */
     69         void setPassFailButtonClickListeners();
     70 
     71         /**
     72          * Adds an initial informational dialog that appears when entering the test activity for
     73          * the first time. Also enables the visibility of an "Info" button between the "Pass" and
     74          * "Fail" buttons that can be clicked to show the information dialog again.
     75          * <p>
     76          * Call from {@link Activity#onCreate} after {@link Activity #setContentView(int)}.
     77          *
     78          * @param titleId for the text shown in the dialog title area
     79          * @param messageId for the text shown in the dialog's body area
     80          */
     81         void setInfoResources(int titleId, int messageId, int viewId);
     82 
     83         View getPassButton();
     84 
     85         /**
     86          * Returns a unique identifier for the test.  Usually, this is just the class name.
     87          */
     88         String getTestId();
     89 
     90         /** @return null or details about the test run. */
     91         String getTestDetails();
     92 
     93         /**
     94          * Set the result of the test and finish the activity.
     95          *
     96          * @param passed Whether or not the test passed.
     97          */
     98         void setTestResultAndFinish(boolean passed);
     99 
    100         /** @return A {@link ReportLog} that is used to record test metric data. */
    101         ReportLog getReportLog();
    102     }
    103 
    104     public static class Activity extends android.app.Activity implements PassFailActivity {
    105         private WakeLock mWakeLock;
    106         private final ReportLog reportLog;
    107 
    108         public Activity() {
    109            this.reportLog = new CtsVerifierReportLog();
    110         }
    111 
    112         @Override
    113         protected void onResume() {
    114             super.onResume();
    115             if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    116                 mWakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE))
    117                         .newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "PassFailButtons");
    118                 mWakeLock.acquire();
    119             }
    120         }
    121 
    122         @Override
    123         protected void onPause() {
    124             super.onPause();
    125             if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
    126                 mWakeLock.release();
    127             }
    128         }
    129 
    130         @Override
    131         public void setPassFailButtonClickListeners() {
    132             setPassFailClickListeners(this);
    133         }
    134 
    135         @Override
    136         public void setInfoResources(int titleId, int messageId, int viewId) {
    137             setInfo(this, titleId, messageId, viewId);
    138         }
    139 
    140         @Override
    141         public View getPassButton() {
    142             return getPassButtonView(this);
    143         }
    144 
    145         @Override
    146         public Dialog onCreateDialog(int id, Bundle args) {
    147             return createDialog(this, id, args);
    148         }
    149 
    150         @Override
    151         public String getTestId() {
    152             return getClass().getName();
    153         }
    154 
    155         @Override
    156         public String getTestDetails() {
    157             return null;
    158         }
    159 
    160         @Override
    161         public void setTestResultAndFinish(boolean passed) {
    162             PassFailButtons.setTestResultAndFinishHelper(
    163                     this, getTestId(), getTestDetails(), passed, getReportLog());
    164         }
    165 
    166         @Override
    167         public ReportLog getReportLog() { return reportLog; }
    168     }
    169 
    170     public static class ListActivity extends android.app.ListActivity implements PassFailActivity {
    171 
    172         private final ReportLog reportLog;
    173 
    174         public ListActivity() {
    175             this.reportLog = new CtsVerifierReportLog();
    176         }
    177 
    178         @Override
    179         public void setPassFailButtonClickListeners() {
    180             setPassFailClickListeners(this);
    181         }
    182 
    183         @Override
    184         public void setInfoResources(int titleId, int messageId, int viewId) {
    185             setInfo(this, titleId, messageId, viewId);
    186         }
    187 
    188         @Override
    189         public View getPassButton() {
    190             return getPassButtonView(this);
    191         }
    192 
    193         @Override
    194         public Dialog onCreateDialog(int id, Bundle args) {
    195             return createDialog(this, id, args);
    196         }
    197 
    198         @Override
    199         public String getTestId() {
    200             return getClass().getName();
    201         }
    202 
    203         @Override
    204         public String getTestDetails() {
    205             return null;
    206         }
    207 
    208         @Override
    209         public void setTestResultAndFinish(boolean passed) {
    210             PassFailButtons.setTestResultAndFinishHelper(
    211                     this, getTestId(), getTestDetails(), passed, getReportLog());
    212         }
    213 
    214         @Override
    215         public ReportLog getReportLog() { return reportLog; }
    216     }
    217 
    218     public static class TestListActivity extends AbstractTestListActivity
    219             implements PassFailActivity {
    220 
    221         private final ReportLog reportLog;
    222 
    223         public TestListActivity() {
    224             this.reportLog = new CtsVerifierReportLog();
    225         }
    226 
    227         @Override
    228         public void setPassFailButtonClickListeners() {
    229             setPassFailClickListeners(this);
    230         }
    231 
    232         @Override
    233         public void setInfoResources(int titleId, int messageId, int viewId) {
    234             setInfo(this, titleId, messageId, viewId);
    235         }
    236 
    237         @Override
    238         public View getPassButton() {
    239             return getPassButtonView(this);
    240         }
    241 
    242         @Override
    243         public Dialog onCreateDialog(int id, Bundle args) {
    244             return createDialog(this, id, args);
    245         }
    246 
    247         @Override
    248         public String getTestId() {
    249             return getClass().getName();
    250         }
    251 
    252         @Override
    253         public String getTestDetails() {
    254             return null;
    255         }
    256 
    257         @Override
    258         public void setTestResultAndFinish(boolean passed) {
    259             PassFailButtons.setTestResultAndFinishHelper(
    260                     this, getTestId(), getTestDetails(), passed, getReportLog());
    261         }
    262 
    263         @Override
    264         public ReportLog getReportLog() { return reportLog; }
    265 
    266         public void updatePassButton() {
    267             getPassButton().setEnabled(mAdapter.allTestsPassed());
    268         }
    269     }
    270 
    271     protected static <T extends android.app.Activity & PassFailActivity>
    272             void setPassFailClickListeners(final T activity) {
    273         View.OnClickListener clickListener = new View.OnClickListener() {
    274             @Override
    275             public void onClick(View target) {
    276                 setTestResultAndFinish(activity, activity.getTestId(), activity.getTestDetails(),
    277                         activity.getReportLog(), target);
    278             }
    279         };
    280 
    281         View passButton = activity.findViewById(R.id.pass_button);
    282         passButton.setOnClickListener(clickListener);
    283         passButton.setOnLongClickListener(new View.OnLongClickListener() {
    284             @Override
    285             public boolean onLongClick(View view) {
    286                 Toast.makeText(activity, R.string.pass_button_text, Toast.LENGTH_SHORT).show();
    287                 return true;
    288             }
    289         });
    290 
    291         View failButton = activity.findViewById(R.id.fail_button);
    292         failButton.setOnClickListener(clickListener);
    293         failButton.setOnLongClickListener(new View.OnLongClickListener() {
    294             @Override
    295             public boolean onLongClick(View view) {
    296                 Toast.makeText(activity, R.string.fail_button_text, Toast.LENGTH_SHORT).show();
    297                 return true;
    298             }
    299         });
    300     }
    301 
    302     protected static void setInfo(final android.app.Activity activity, final int titleId,
    303             final int messageId, final int viewId) {
    304         // Show the middle "info" button and make it show the info dialog when clicked.
    305         View infoButton = activity.findViewById(R.id.info_button);
    306         infoButton.setVisibility(View.VISIBLE);
    307         infoButton.setOnClickListener(new OnClickListener() {
    308             @Override
    309             public void onClick(View view) {
    310                 showInfoDialog(activity, titleId, messageId, viewId);
    311             }
    312         });
    313         infoButton.setOnLongClickListener(new View.OnLongClickListener() {
    314             @Override
    315             public boolean onLongClick(View view) {
    316                 Toast.makeText(activity, R.string.info_button_text, Toast.LENGTH_SHORT).show();
    317                 return true;
    318             }
    319         });
    320 
    321         // Show the info dialog if the user has never seen it before.
    322         if (!hasSeenInfoDialog(activity)) {
    323             showInfoDialog(activity, titleId, messageId, viewId);
    324         }
    325     }
    326 
    327     protected static boolean hasSeenInfoDialog(android.app.Activity activity) {
    328         ContentResolver resolver = activity.getContentResolver();
    329         Cursor cursor = null;
    330         try {
    331             cursor = resolver.query(TestResultsProvider.getTestNameUri(activity),
    332                     new String[] {TestResultsProvider.COLUMN_TEST_INFO_SEEN}, null, null, null);
    333             return cursor.moveToFirst() && cursor.getInt(0) > 0;
    334         } finally {
    335             if (cursor != null) {
    336                 cursor.close();
    337             }
    338         }
    339     }
    340 
    341     protected static void showInfoDialog(final android.app.Activity activity, int titleId,
    342             int messageId, int viewId) {
    343         Bundle args = new Bundle();
    344         args.putInt(INFO_DIALOG_TITLE_ID, titleId);
    345         args.putInt(INFO_DIALOG_MESSAGE_ID, messageId);
    346         args.putInt(INFO_DIALOG_VIEW_ID, viewId);
    347         activity.showDialog(INFO_DIALOG_ID, args);
    348     }
    349 
    350     protected static Dialog createDialog(final android.app.Activity activity, int id, Bundle args) {
    351         switch (id) {
    352             case INFO_DIALOG_ID:
    353                 return createInfoDialog(activity, id, args);
    354             default:
    355                 throw new IllegalArgumentException("Bad dialog id: " + id);
    356         }
    357     }
    358 
    359     protected static Dialog createInfoDialog(final android.app.Activity activity, int id,
    360             Bundle args) {
    361         int viewId = args.getInt(INFO_DIALOG_VIEW_ID);
    362         int titleId = args.getInt(INFO_DIALOG_TITLE_ID);
    363         int messageId = args.getInt(INFO_DIALOG_MESSAGE_ID);
    364 
    365         AlertDialog.Builder builder = new AlertDialog.Builder(activity).setIcon(
    366                 android.R.drawable.ic_dialog_info).setTitle(titleId);
    367         if (viewId > 0) {
    368             LayoutInflater inflater = (LayoutInflater) activity
    369                     .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    370             builder.setView(inflater.inflate(viewId, null));
    371         } else {
    372             builder.setMessage(messageId);
    373         }
    374         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    375             @Override
    376             public void onClick(DialogInterface dialog, int which) {
    377                 markSeenInfoDialog(activity);
    378             }
    379         }).setOnCancelListener(new OnCancelListener() {
    380             @Override
    381             public void onCancel(DialogInterface dialog) {
    382                 markSeenInfoDialog(activity);
    383             }
    384         });
    385         return builder.create();
    386     }
    387 
    388     protected static void markSeenInfoDialog(android.app.Activity activity) {
    389         ContentResolver resolver = activity.getContentResolver();
    390         ContentValues values = new ContentValues(2);
    391         values.put(TestResultsProvider.COLUMN_TEST_NAME, activity.getClass().getName());
    392         values.put(TestResultsProvider.COLUMN_TEST_INFO_SEEN, 1);
    393         int numUpdated = resolver.update(
    394                 TestResultsProvider.getTestNameUri(activity), values, null, null);
    395         if (numUpdated == 0) {
    396             resolver.insert(TestResultsProvider.getResultContentUri(activity), values);
    397         }
    398     }
    399 
    400     /** Set the test result corresponding to the button clicked and finish the activity. */
    401     protected static void setTestResultAndFinish(android.app.Activity activity, String testId,
    402             String testDetails, ReportLog reportLog, View target) {
    403         boolean passed;
    404         if (target.getId() == R.id.pass_button) {
    405             passed = true;
    406         } else if (target.getId() == R.id.fail_button) {
    407             passed = false;
    408         } else {
    409             throw new IllegalArgumentException("Unknown id: " + target.getId());
    410         }
    411 
    412         setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog);
    413     }
    414 
    415     /** Set the test result and finish the activity. */
    416     protected static void setTestResultAndFinishHelper(android.app.Activity activity, String testId,
    417             String testDetails, boolean passed, ReportLog reportLog) {
    418         if (passed) {
    419             TestResult.setPassedResult(activity, testId, testDetails, reportLog);
    420         } else {
    421             TestResult.setFailedResult(activity, testId, testDetails, reportLog);
    422         }
    423 
    424         activity.finish();
    425     }
    426 
    427     protected static ImageButton getPassButtonView(android.app.Activity activity) {
    428         return (ImageButton) activity.findViewById(R.id.pass_button);
    429     }
    430 
    431     public static class CtsVerifierReportLog extends ReportLog {
    432 
    433     }
    434 }
    435