Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 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 android.widget.cts;
     18 
     19 import com.android.cts.widget.R;
     20 
     21 
     22 import android.content.Context;
     23 import android.cts.util.WidgetTestUtils;
     24 import android.database.Cursor;
     25 import android.database.MatrixCursor;
     26 import android.graphics.Bitmap;
     27 import android.graphics.drawable.BitmapDrawable;
     28 import android.test.InstrumentationTestCase;
     29 import android.test.UiThreadTest;
     30 import android.view.LayoutInflater;
     31 import android.view.View;
     32 import android.view.ViewGroup;
     33 import android.widget.ImageView;
     34 import android.widget.LinearLayout;
     35 import android.widget.SimpleCursorAdapter;
     36 import android.widget.TextView;
     37 import android.widget.SimpleCursorAdapter.CursorToStringConverter;
     38 import android.widget.SimpleCursorAdapter.ViewBinder;
     39 
     40 import java.io.IOException;
     41 import java.io.InputStream;
     42 import java.io.OutputStream;
     43 
     44 /**
     45  * Test {@link SimpleCursorAdapter}.
     46  * The simple cursor adapter's cursor will be set to
     47  * {@link SimpleCursorAdapterTest#mCursor} It will use internal
     48  * R.layout.simple_list_item_1.
     49  */
     50 public class SimpleCursorAdapterTest extends InstrumentationTestCase {
     51     private static final int ADAPTER_ROW_COUNT = 20;
     52 
     53     private static final int DEFAULT_COLUMN_COUNT = 2;
     54 
     55     private static final int[] VIEWS_TO = new int[] { R.id.cursorAdapter_item0 };
     56 
     57     private static final String[] COLUMNS_FROM = new String[] { "column1" };
     58 
     59     private static final String SAMPLE_IMAGE_NAME = "testimage.jpg";
     60 
     61     private Context mContext;
     62 
     63     /**
     64      * The original cursor and its content will be set to:
     65      * <TABLE>
     66      * <TR>
     67      * <TH>Column0</TH>
     68      * <TH>Column1</TH>
     69      * </TR>
     70      * <TR>
     71      * <TD>00</TD>
     72      * <TD>01</TD>
     73      * </TR>
     74      * <TR>
     75      * <TD>10</TD>
     76      * <TD>11</TD>
     77      * </TR>
     78      * <TR>
     79      * <TD>...</TD>
     80      * <TD>...</TD>
     81      * </TR>
     82      * <TR>
     83      * <TD>190</TD>
     84      * <TD>191</TD>
     85      * </TR>
     86      * </TABLE>
     87      * It has 2 columns and 20 rows
     88      */
     89     private Cursor mCursor;
     90 
     91     @Override
     92     protected void setUp() throws Exception {
     93         super.setUp();
     94         mContext = getInstrumentation().getTargetContext();
     95 
     96         mCursor = createTestCursor(DEFAULT_COLUMN_COUNT, ADAPTER_ROW_COUNT);
     97     }
     98 
     99     private SimpleCursorAdapter makeSimpleCursorAdapter() {
    100         return new SimpleCursorAdapter(
    101                 mContext, R.layout.cursoradapter_item0, mCursor, COLUMNS_FROM, VIEWS_TO);
    102     }
    103 
    104     @UiThreadTest
    105     public void testConstructor() {
    106         new SimpleCursorAdapter(mContext, R.layout.cursoradapter_item0,
    107                 createTestCursor(DEFAULT_COLUMN_COUNT, ADAPTER_ROW_COUNT),
    108                 COLUMNS_FROM, VIEWS_TO);
    109     }
    110 
    111     @UiThreadTest
    112     public void testBindView() {
    113         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    114         TextView listItem = (TextView) simpleCursorAdapter.newView(mContext, null, null);
    115 
    116         listItem.setText("");
    117         mCursor.moveToFirst();
    118         simpleCursorAdapter.bindView(listItem, null, mCursor);
    119         assertEquals("01", listItem.getText().toString());
    120 
    121         mCursor.moveToLast();
    122         simpleCursorAdapter.bindView(listItem, null, mCursor);
    123         assertEquals("191", listItem.getText().toString());
    124 
    125         // the binder take care of binding
    126         listItem.setText("");
    127         MockViewBinder binder = new MockViewBinder(true);
    128         simpleCursorAdapter.setViewBinder(binder);
    129         binder.reset();
    130         mCursor.moveToFirst();
    131         simpleCursorAdapter.bindView(listItem, null, mCursor);
    132         assertTrue(binder.hasCalledSetViewValueCalledCount());
    133         assertEquals("", listItem.getText().toString());
    134 
    135         // the binder try to bind but fail
    136         binder = new MockViewBinder(false);
    137         simpleCursorAdapter.setViewBinder(binder);
    138         mCursor.moveToLast();
    139         simpleCursorAdapter.bindView(listItem, null, mCursor);
    140         assertTrue(binder.hasCalledSetViewValueCalledCount());
    141         assertEquals("191", listItem.getText().toString());
    142 
    143         final int [] to = { R.id.cursorAdapter_host };
    144         simpleCursorAdapter = new SimpleCursorAdapter(mContext, R.layout.cursoradapter_host,
    145                 mCursor, COLUMNS_FROM, to);
    146         LinearLayout illegalView = (LinearLayout)simpleCursorAdapter.newView(mContext, null, null);
    147         try {
    148             // The IllegalStateException already gets thrown in the line above.
    149             simpleCursorAdapter.bindView(illegalView, null, mCursor);
    150             fail("Should throw IllegalStateException if the view is not TextView or ImageView");
    151         } catch (IllegalStateException e) {
    152             // expected
    153         }
    154     }
    155 
    156     @UiThreadTest
    157     public void testAccessViewBinder() {
    158         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    159         assertNull(simpleCursorAdapter.getViewBinder());
    160 
    161         MockViewBinder binder = new MockViewBinder(true);
    162         simpleCursorAdapter.setViewBinder(binder);
    163         assertSame(binder, simpleCursorAdapter.getViewBinder());
    164 
    165         binder = new MockViewBinder(false);
    166         simpleCursorAdapter.setViewBinder(binder);
    167         assertSame(binder, simpleCursorAdapter.getViewBinder());
    168 
    169         simpleCursorAdapter.setViewBinder(null);
    170         assertNull(simpleCursorAdapter.getViewBinder());
    171     }
    172 
    173     @UiThreadTest
    174     public void testSetViewText() {
    175         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    176         TextView view = new TextView(mContext);
    177         simpleCursorAdapter.setViewText(view, "expected");
    178         assertEquals("expected", view.getText().toString());
    179 
    180         simpleCursorAdapter.setViewText(view, null);
    181         assertEquals("", view.getText().toString());
    182     }
    183 
    184     @UiThreadTest
    185     public void testSetViewImage() {
    186         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    187         // resId
    188         int sceneryImgResId = com.android.cts.widget.R.drawable.scenery;
    189         ImageView view = new ImageView(mContext);
    190         assertNull(view.getDrawable());
    191         simpleCursorAdapter.setViewImage(view, String.valueOf(sceneryImgResId));
    192         assertNotNull(view.getDrawable());
    193         BitmapDrawable d = (BitmapDrawable) mContext.getResources().getDrawable(
    194                 sceneryImgResId);
    195         WidgetTestUtils.assertEquals(d.getBitmap(),
    196                 ((BitmapDrawable) view.getDrawable()).getBitmap());
    197 
    198         // blank
    199         view = new ImageView(mContext);
    200         assertNull(view.getDrawable());
    201         simpleCursorAdapter.setViewImage(view, "");
    202         assertNull(view.getDrawable());
    203 
    204         // null
    205         view = new ImageView(mContext);
    206         assertNull(view.getDrawable());
    207         try {
    208             // Should declare NullPoinertException if the uri or value is null
    209             simpleCursorAdapter.setViewImage(view, null);
    210             fail("Should throw NullPointerException if the uri or value is null");
    211         } catch (NullPointerException e) {
    212             // expected
    213         }
    214 
    215         // uri
    216         view = new ImageView(mContext);
    217         assertNull(view.getDrawable());
    218         try {
    219             int testimgRawId = com.android.cts.widget.R.raw.testimage;
    220             simpleCursorAdapter.setViewImage(view,
    221                     createTestImage(mContext, SAMPLE_IMAGE_NAME, testimgRawId));
    222             assertNotNull(view.getDrawable());
    223             Bitmap actualBitmap = ((BitmapDrawable) view.getDrawable()).getBitmap();
    224             Bitmap testBitmap = WidgetTestUtils.getUnscaledAndDitheredBitmap(mContext.getResources(),
    225                     testimgRawId, actualBitmap.getConfig());
    226             WidgetTestUtils.assertEquals(testBitmap, actualBitmap);
    227         } finally {
    228             destroyTestImage(mContext, SAMPLE_IMAGE_NAME);
    229         }
    230     }
    231 
    232     @UiThreadTest
    233     public void testAccessStringConversionColumn() {
    234         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    235         // default is -1
    236         assertEquals(-1, simpleCursorAdapter.getStringConversionColumn());
    237 
    238         simpleCursorAdapter.setStringConversionColumn(1);
    239         assertEquals(1, simpleCursorAdapter.getStringConversionColumn());
    240 
    241         // Should check whether the column index is out of bounds
    242         simpleCursorAdapter.setStringConversionColumn(Integer.MAX_VALUE);
    243         assertEquals(Integer.MAX_VALUE, simpleCursorAdapter.getStringConversionColumn());
    244 
    245         // Should check whether the column index is out of bounds
    246         simpleCursorAdapter.setStringConversionColumn(Integer.MIN_VALUE);
    247         assertEquals(Integer.MIN_VALUE, simpleCursorAdapter.getStringConversionColumn());
    248     }
    249 
    250     @UiThreadTest
    251     public void testAccessCursorToStringConverter() {
    252         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    253         // default is null
    254         assertNull(simpleCursorAdapter.getCursorToStringConverter());
    255 
    256         CursorToStringConverter converter = new MockCursorToStringConverter();
    257         simpleCursorAdapter.setCursorToStringConverter(converter);
    258         assertSame(converter, simpleCursorAdapter.getCursorToStringConverter());
    259 
    260         simpleCursorAdapter.setCursorToStringConverter(null);
    261         assertNull(simpleCursorAdapter.getCursorToStringConverter());
    262     }
    263 
    264     @UiThreadTest
    265     public void testChangeCursor() {
    266         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    267         // have "column1"
    268         Cursor curWith3Columns = createTestCursor(3, ADAPTER_ROW_COUNT);
    269         simpleCursorAdapter.changeCursor(curWith3Columns);
    270         assertSame(curWith3Columns, simpleCursorAdapter.getCursor());
    271 
    272         // does not have "column1"
    273         Cursor curWith1Column = createTestCursor(1, ADAPTER_ROW_COUNT);
    274         try {
    275             simpleCursorAdapter.changeCursor(curWith1Column);
    276             fail("Should throw exception if the cursor does not have the "
    277                     + "original column passed in the constructor");
    278         } catch (IllegalArgumentException e) {
    279             // expected
    280         }
    281     }
    282 
    283     @UiThreadTest
    284     public void testConvertToString() {
    285         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    286         mCursor.moveToFirst();
    287         assertEquals("", simpleCursorAdapter.convertToString(null));
    288 
    289         // converter is null, StringConversionColumn is set to negative
    290         simpleCursorAdapter.setStringConversionColumn(Integer.MIN_VALUE);
    291         assertEquals(mCursor.toString(), simpleCursorAdapter.convertToString(mCursor));
    292 
    293         // converter is null, StringConversionColumn is set to 1
    294         simpleCursorAdapter.setStringConversionColumn(1);
    295         assertEquals("01", simpleCursorAdapter.convertToString(mCursor));
    296 
    297         // converter is null, StringConversionColumn is set to 3 (larger than columns count)
    298         // the cursor has 3 columns including column0, column1 and _id which is added automatically
    299         simpleCursorAdapter.setStringConversionColumn(DEFAULT_COLUMN_COUNT + 1);
    300         try {
    301             simpleCursorAdapter.convertToString(mCursor);
    302             fail("Should throw IndexOutOfBoundsException if index is beyond the columns count");
    303         } catch (IndexOutOfBoundsException e) {
    304             // expected
    305         }
    306 
    307         Cursor curWith3Columns = createTestCursor(DEFAULT_COLUMN_COUNT + 1, ADAPTER_ROW_COUNT);
    308         curWith3Columns.moveToFirst();
    309 
    310         // converter is null, StringConversionColumn is set to 3
    311         // and covert with a cursor which has 4 columns
    312         simpleCursorAdapter.setStringConversionColumn(2);
    313         assertEquals("02", simpleCursorAdapter.convertToString(curWith3Columns));
    314 
    315         // converter is not null, StringConversionColumn is 1
    316         CursorToStringConverter converter = new MockCursorToStringConverter();
    317         simpleCursorAdapter.setCursorToStringConverter(converter);
    318         simpleCursorAdapter.setStringConversionColumn(1);
    319         ((MockCursorToStringConverter) converter).reset();
    320         simpleCursorAdapter.convertToString(curWith3Columns);
    321         assertTrue(((MockCursorToStringConverter) converter).hasCalledConvertToString());
    322     }
    323 
    324     @UiThreadTest
    325     public void testNewView() {
    326         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    327         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
    328                 Context.LAYOUT_INFLATER_SERVICE);
    329         ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(
    330                 com.android.cts.widget.R.layout.cursoradapter_host, null);
    331         View result = simpleCursorAdapter.newView(mContext, null, viewGroup);
    332         assertNotNull(result);
    333         assertEquals(R.id.cursorAdapter_item0, result.getId());
    334 
    335         result = simpleCursorAdapter.newView(mContext, null, null);
    336         assertNotNull(result);
    337         assertEquals(R.id.cursorAdapter_item0, result.getId());
    338     }
    339 
    340     @UiThreadTest
    341     public void testNewDropDownView() {
    342         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    343         LayoutInflater layoutInflater = (LayoutInflater) mContext.getSystemService(
    344                 Context.LAYOUT_INFLATER_SERVICE);
    345         ViewGroup viewGroup = (ViewGroup) layoutInflater.inflate(
    346                 com.android.cts.widget.R.layout.cursoradapter_host, null);
    347         View result = simpleCursorAdapter.newDropDownView(null, null, viewGroup);
    348         assertNotNull(result);
    349         assertEquals(R.id.cursorAdapter_item0, result.getId());
    350     }
    351 
    352     @UiThreadTest
    353     public void testChangeCursorAndColumns() {
    354         SimpleCursorAdapter simpleCursorAdapter = makeSimpleCursorAdapter();
    355         assertSame(mCursor, simpleCursorAdapter.getCursor());
    356 
    357         TextView listItem = (TextView) simpleCursorAdapter.newView(mContext, null, null);
    358 
    359         mCursor.moveToFirst();
    360         simpleCursorAdapter.bindView(listItem, null, mCursor);
    361         assertEquals("01", listItem.getText().toString());
    362 
    363         mCursor.moveToLast();
    364         simpleCursorAdapter.bindView(listItem, null, mCursor);
    365         assertEquals("191", listItem.getText().toString());
    366 
    367         Cursor newCursor = createTestCursor(3, ADAPTER_ROW_COUNT);
    368         final String[] from = new String[] { "column2" };
    369         simpleCursorAdapter.changeCursorAndColumns(newCursor, from, VIEWS_TO);
    370         assertSame(newCursor, simpleCursorAdapter.getCursor());
    371         newCursor.moveToFirst();
    372         simpleCursorAdapter.bindView(listItem, null, newCursor);
    373         assertEquals("02", listItem.getText().toString());
    374 
    375         newCursor.moveToLast();
    376         simpleCursorAdapter.bindView(listItem, null, newCursor);
    377         assertEquals("192", listItem.getText().toString());
    378 
    379         simpleCursorAdapter.changeCursorAndColumns(null, null, null);
    380         assertNull(simpleCursorAdapter.getCursor());
    381     }
    382 
    383     /**
    384      * Creates the test cursor.
    385      *
    386      * @param colCount the column count
    387      * @param rowCount the row count
    388      * @return the cursor
    389      */
    390     @SuppressWarnings("unchecked")
    391     private Cursor createTestCursor(int colCount, int rowCount) {
    392         String[] columns = new String[colCount + 1];
    393         for (int i = 0; i < colCount; i++) {
    394             columns[i] = "column" + i;
    395         }
    396         columns[colCount] = "_id";
    397 
    398         MatrixCursor cursor = new MatrixCursor(columns, rowCount);
    399         Object[] row = new Object[colCount + 1];
    400         for (int i = 0; i < rowCount; i++) {
    401             for (int j = 0; j < colCount; j++) {
    402                 row[j] = "" + i + "" + j;
    403             }
    404             row[colCount] = i;
    405             cursor.addRow(row);
    406         }
    407         return cursor;
    408     }
    409 
    410     private static class MockViewBinder implements ViewBinder {
    411         private boolean mExpectedResult;
    412 
    413         private boolean mHasCalledSetViewValue;
    414 
    415         public MockViewBinder(boolean expectedResult) {
    416             mExpectedResult = expectedResult;
    417         }
    418 
    419         public void reset(){
    420             mHasCalledSetViewValue = false;
    421         }
    422 
    423         public boolean hasCalledSetViewValueCalledCount() {
    424             return mHasCalledSetViewValue;
    425         }
    426 
    427         public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
    428             mHasCalledSetViewValue = true;
    429             return mExpectedResult;
    430         }
    431     }
    432 
    433     public static String createTestImage(Context context, String fileName, int resId) {
    434         InputStream source = null;
    435         OutputStream target = null;
    436 
    437         try {
    438             source = context.getResources().openRawResource(resId);
    439             target = context.openFileOutput(fileName, Context.MODE_WORLD_WRITEABLE);
    440 
    441             byte[] buffer = new byte[1024];
    442             for (int len = source.read(buffer); len > 0; len = source.read(buffer)) {
    443                 target.write(buffer, 0, len);
    444             }
    445         } catch (IOException e) {
    446             fail(e.getMessage());
    447         } finally {
    448             try {
    449                 if (source != null) {
    450                     source.close();
    451                 }
    452                 if (target != null) {
    453                     target.close();
    454                 }
    455             } catch (IOException e) {
    456                 // Ignore the IOException.
    457             }
    458         }
    459 
    460         return context.getFileStreamPath(fileName).getAbsolutePath();
    461     }
    462 
    463     public static void destroyTestImage(Context context, String fileName) {
    464         context.deleteFile(fileName);
    465     }
    466 
    467     private static class MockCursorToStringConverter implements CursorToStringConverter {
    468         private boolean mHasCalledConvertToString;
    469 
    470         public boolean hasCalledConvertToString() {
    471             return mHasCalledConvertToString;
    472         }
    473 
    474         public void reset(){
    475             mHasCalledConvertToString = false;
    476         }
    477 
    478         public CharSequence convertToString(Cursor cursor) {
    479             mHasCalledConvertToString = true;
    480             return null;
    481         }
    482     }
    483 }
    484