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.app.cts; 18 19 import android.app.AlertDialog; 20 import android.app.AlertDialog.Builder; 21 import android.app.Instrumentation; 22 import android.app.stubs.DialogStubActivity; 23 import android.content.ContentValues; 24 import android.content.Context; 25 import android.content.DialogInterface; 26 import android.content.DialogInterface.OnClickListener; 27 import android.content.DialogInterface.OnMultiChoiceClickListener; 28 import android.database.Cursor; 29 import android.database.sqlite.SQLiteCursor; 30 import android.database.sqlite.SQLiteDatabase; 31 import android.support.test.InstrumentationRegistry; 32 import android.test.ActivityInstrumentationTestCase2; 33 import android.test.suitebuilder.annotation.MediumTest; 34 import android.widget.ListView; 35 36 import com.android.compatibility.common.util.PollingCheck; 37 38 import java.io.File; 39 40 import static org.mockito.Mockito.*; 41 42 @MediumTest 43 public class AlertDialog_BuilderCursorTest 44 extends ActivityInstrumentationTestCase2<DialogStubActivity> { 45 private Builder mBuilder; 46 private Context mContext; 47 private Instrumentation mInstrumentation; 48 private AlertDialog mDialog; 49 private ListView mListView; 50 51 private static final String TEXT_COLUMN_NAME = "text"; 52 private static final String CHECKED_COLUMN_NAME = "checked"; 53 54 private String[] mTextContent; 55 private boolean[] mCheckedContent; 56 57 private String[] mProjectionWithChecked; 58 private String[] mProjectionWithoutChecked; 59 60 private SQLiteDatabase mDatabase; 61 private File mDatabaseFile; 62 private Cursor mCursor; 63 64 private OnClickListener mOnClickListener = mock(OnClickListener.class); 65 66 /** 67 * Multi-choice click listener that is registered on our {@link AlertDialog} when it's in 68 * multi-choide mode. Note that this needs to be a separate class that is also protected (not 69 * private) so that Mockito can "spy" on it. 70 */ 71 protected class MultiChoiceClickListener implements OnMultiChoiceClickListener { 72 private boolean[] mCheckedTracker; 73 74 public MultiChoiceClickListener(boolean[] checkedTracker) { 75 mCheckedTracker = checkedTracker; 76 } 77 78 @Override 79 public void onClick(DialogInterface dialog, int which, 80 boolean isChecked) { 81 // Update the underlying database with the new checked 82 // state for the specific row 83 mCursor.moveToPosition(which); 84 ContentValues valuesToUpdate = new ContentValues(); 85 valuesToUpdate.put(CHECKED_COLUMN_NAME, isChecked ? 1 : 0); 86 mDatabase.update("test", valuesToUpdate, 87 TEXT_COLUMN_NAME + " = ?", 88 new String[] { mCursor.getString(1) } ); 89 mCursor.requery(); 90 mCheckedTracker[which] = isChecked; 91 } 92 } 93 94 public AlertDialog_BuilderCursorTest() { 95 super("android.app.stubs", DialogStubActivity.class); 96 } 97 98 @Override 99 protected void setUp() throws Exception { 100 super.setUp(); 101 mBuilder = null; 102 mInstrumentation = getInstrumentation(); 103 mContext = getActivity(); 104 105 PollingCheck.waitFor(() -> getActivity().hasWindowFocus()); 106 107 mListView = null; 108 mDialog = null; 109 110 // Local test data for the tests 111 mTextContent = new String[] { "Adele", "Beyonce", "Ciara", "Dido" }; 112 mCheckedContent = new boolean[] { false, false, true, false }; 113 114 // Two projections - one with "checked" column and one without 115 mProjectionWithChecked = new String[] { 116 "_id", // 0 117 TEXT_COLUMN_NAME, // 1 118 CHECKED_COLUMN_NAME // 2 119 }; 120 mProjectionWithoutChecked = new String[] { 121 "_id", // 0 122 TEXT_COLUMN_NAME // 1 123 }; 124 125 File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE); 126 mDatabaseFile = new File(dbDir, "database_alert_dialog_test.db"); 127 if (mDatabaseFile.exists()) { 128 mDatabaseFile.delete(); 129 } 130 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); 131 assertNotNull(mDatabase); 132 // Create and populate a test table 133 mDatabase.execSQL( 134 "CREATE TABLE test (_id INTEGER PRIMARY KEY, " + TEXT_COLUMN_NAME + 135 " TEXT, " + CHECKED_COLUMN_NAME + " INTEGER);"); 136 for (int i = 0; i < mTextContent.length; i++) { 137 mDatabase.execSQL("INSERT INTO test (" + TEXT_COLUMN_NAME + ", " + 138 CHECKED_COLUMN_NAME + ") VALUES ('" + mTextContent[i] + "', " + 139 (mCheckedContent[i] ? "1" : "0") + ");"); 140 } 141 } 142 143 @Override 144 protected void tearDown() throws Exception { 145 if (mCursor != null) { 146 // Close the cursor on the UI thread as the list view in the alert dialog 147 // will get notified of any change to the underlying cursor. 148 InstrumentationRegistry.getInstrumentation().runOnMainSync( 149 () -> { 150 mCursor.close(); 151 mCursor = null; 152 }); 153 } 154 if (mDatabase != null) { 155 mDatabase.close(); 156 } 157 if (mDatabaseFile != null) { 158 mDatabaseFile.delete(); 159 } 160 161 super.tearDown(); 162 } 163 164 public void testSetCursor() throws Throwable { 165 // Use a projection without "checked" column 166 mCursor = mDatabase.query("test", mProjectionWithoutChecked, 167 null, null, null, null, null); 168 assertNotNull(mCursor); 169 170 runTestOnUiThread( 171 () -> { 172 mBuilder = new Builder(mContext); 173 mBuilder.setCursor(mCursor, mOnClickListener, TEXT_COLUMN_NAME); 174 mDialog = mBuilder.show(); 175 mListView = mDialog.getListView(); 176 mListView.performItemClick(null, 0, 0); 177 }); 178 mInstrumentation.waitForIdleSync(); 179 final SQLiteCursor selected = (SQLiteCursor) mListView.getSelectedItem(); 180 assertEquals(mCursor.getString(1), selected.getString(1)); 181 verify(mOnClickListener, times(1)).onClick(mDialog, 0); 182 verifyNoMoreInteractions(mOnClickListener); 183 } 184 185 public void testSetSingleChoiceItemsWithParamCursor() throws Throwable { 186 // Use a projection without "checked" column 187 mCursor = mDatabase.query("test", mProjectionWithoutChecked, 188 null, null, null, null, null); 189 assertNotNull(mCursor); 190 191 runTestOnUiThread( 192 () -> { 193 mBuilder = new Builder(mContext); 194 mBuilder.setSingleChoiceItems(mCursor, 0, TEXT_COLUMN_NAME, mOnClickListener); 195 mDialog = mBuilder.show(); 196 mListView = mDialog.getListView(); 197 mListView.performItemClick(null, 0, 0); 198 }); 199 mInstrumentation.waitForIdleSync(); 200 final SQLiteCursor selected = (SQLiteCursor) mListView.getSelectedItem(); 201 assertEquals(mCursor.getString(1), selected.getString(1)); 202 verify(mOnClickListener, times(1)).onClick(mDialog, 0); 203 verifyNoMoreInteractions(mOnClickListener); 204 } 205 206 public void testSetMultiChoiceItemsWithParamCursor() throws Throwable { 207 mCursor = mDatabase.query("test", mProjectionWithChecked, 208 null, null, null, null, null); 209 assertNotNull(mCursor); 210 211 final boolean[] checkedTracker = mCheckedContent.clone(); 212 final OnMultiChoiceClickListener mockMultiChoiceClickListener = 213 spy(new MultiChoiceClickListener(checkedTracker)); 214 runTestOnUiThread( 215 () -> { 216 mBuilder = new Builder(mContext); 217 mBuilder.setMultiChoiceItems(mCursor, CHECKED_COLUMN_NAME, TEXT_COLUMN_NAME, 218 mockMultiChoiceClickListener); 219 mDialog = mBuilder.show(); 220 mListView = mDialog.getListView(); 221 mListView.performItemClick(null, 0, 0); 222 }); 223 mInstrumentation.waitForIdleSync(); 224 225 SQLiteCursor selected = (SQLiteCursor) mListView.getSelectedItem(); 226 assertEquals(mCursor.getString(0), selected.getString(0)); 227 verify(mockMultiChoiceClickListener, times(1)).onClick(mDialog, 0, true); 228 // Verify that our multi-choice listener was invoked to update our tracker array 229 assertTrue(checkedTracker[0]); 230 assertFalse(checkedTracker[1]); 231 assertTrue(checkedTracker[2]); 232 assertFalse(checkedTracker[3]); 233 234 runTestOnUiThread(() -> mListView.performItemClick(null, 1, 1)); 235 mInstrumentation.waitForIdleSync(); 236 237 selected = (SQLiteCursor) mListView.getSelectedItem(); 238 assertEquals(mCursor.getString(1), selected.getString(1)); 239 verify(mockMultiChoiceClickListener, times(1)).onClick(mDialog, 1, true); 240 // Verify that our multi-choice listener was invoked to update our tracker array 241 assertTrue(checkedTracker[0]); 242 assertTrue(checkedTracker[1]); 243 assertTrue(checkedTracker[2]); 244 assertFalse(checkedTracker[3]); 245 246 verifyNoMoreInteractions(mockMultiChoiceClickListener); 247 } 248 } 249