diff options
| author | Bjorn Bringert <bringert@android.com> | 2009-06-05 13:22:28 +0100 |
|---|---|---|
| committer | Bjorn Bringert <bringert@android.com> | 2009-06-15 09:05:26 +0100 |
| commit | 8d17f3f24bbda9a9cd7ea08c5925508dc2c011be (patch) | |
| tree | cf7e5ebb721354bfffc41d2ab4932cb70ea3c033 /tests | |
| parent | 3d59ee7aa66a5b1e80f5042f8d872dd9819b5f40 (diff) | |
| download | frameworks_base-8d17f3f24bbda9a9cd7ea08c5925508dc2c011be.zip frameworks_base-8d17f3f24bbda9a9cd7ea08c5925508dc2c011be.tar.gz frameworks_base-8d17f3f24bbda9a9cd7ea08c5925508dc2c011be.tar.bz2 | |
Run search dialog in the system process.
Fixes http://b/issue?id=1905863
This is needed to address two security issues with global search:
http://b/issue?id=1871088 (Apps can read content providers through GlobalSearch)
http://b/issue?id=1819627 (Apps can use GlobalSearch to launch arbirtrary intents)
This also fixes http://b/issue?id=1693153 (SearchManager.OnDismissListener
never gets called)
To fix the security issues, GlobalSearch also needs to require
a non-app permission to access its content provider and launch intents.
Diffstat (limited to 'tests')
6 files changed, 312 insertions, 39 deletions
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml index fd6e6d8..55d4d64 100644 --- a/tests/AndroidTests/AndroidManifest.xml +++ b/tests/AndroidTests/AndroidManifest.xml @@ -219,7 +219,20 @@ </service> <!-- Application components used for search manager tests --> - <!-- TODO: Removed temporarily - need to be replaced using mocks --> + + <activity android:name=".SearchableActivity" + android:label="Searchable Activity"> + <intent-filter> + <action android:name="android.intent.action.SEARCH" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + <meta-data android:name="android.app.searchable" + android:resource="@xml/searchable" /> + </activity> + + <provider android:name=".SuggestionProvider" + android:authorities="com.android.unit_tests.SuggestionProvider"> + </provider> <!-- Used to test IPC. --> <service android:name=".binder.BinderTestService" diff --git a/tests/AndroidTests/res/values/strings.xml b/tests/AndroidTests/res/values/strings.xml index 21c72cf..49d8ae7 100644 --- a/tests/AndroidTests/res/values/strings.xml +++ b/tests/AndroidTests/res/values/strings.xml @@ -50,5 +50,8 @@ <item quantity="other">Some dogs</item> </plurals> + <string name="searchable_label">SearchManager Test</string> + <string name="searchable_hint">A search hint</string> + <!-- <string name="layout_six_text_text">F</string> --> </resources> diff --git a/tests/AndroidTests/res/xml/searchable.xml b/tests/AndroidTests/res/xml/searchable.xml index a40d53d..9d293b5 100644 --- a/tests/AndroidTests/res/xml/searchable.xml +++ b/tests/AndroidTests/res/xml/searchable.xml @@ -15,7 +15,12 @@ --> <searchable xmlns:android="http://schemas.android.com/apk/res/android" - android:label="SearchManagerTest" - android:hint="SearchManagerTest Hint" -/> + android:label="@string/searchable_label" + android:hint="@string/searchable_hint" + android:searchSuggestAuthority="com.android.unit_tests.SuggestionProvider" + > + <actionkey android:keycode="KEYCODE_CALL" + android:suggestActionMsgColumn="suggest_action_msg_call" /> + +</searchable>
\ No newline at end of file diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java index f3c1542..f03a779 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java @@ -23,7 +23,10 @@ import android.app.ISearchManager; import android.app.SearchManager; import android.content.ComponentName; import android.content.Context; +import android.os.Bundle; +import android.os.RemoteException; import android.os.ServiceManager; +import android.server.search.SearchableInfo; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; @@ -37,12 +40,11 @@ import android.util.AndroidRuntimeException; * com.android.unit_tests/android.test.InstrumentationTestRunner */ public class SearchManagerTest extends ActivityInstrumentationTestCase2<LocalActivity> { - - // If non-zero, enable a set of tests that start and stop the search manager. - // This is currently disabled because it's causing an unwanted jump from the unit test - // activity into the contacts activity. We'll put this back after we disable that jump. - private static final int TEST_SEARCH_START = 0; - + + private ComponentName SEARCHABLE_ACTIVITY = + new ComponentName("com.android.unit_tests", + "com.android.unit_tests.SearchableActivity"); + /* * Bug list of test ideas. * @@ -88,7 +90,30 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase2<LocalAct super.setUp(); Activity testActivity = getActivity(); - mContext = (Context)testActivity; + mContext = testActivity; + } + + private ISearchManager getSearchManagerService() { + return ISearchManager.Stub.asInterface( + ServiceManager.getService(Context.SEARCH_SERVICE)); + } + + // Checks that the search UI is visible. + private void assertSearchVisible() { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertTrue("SearchManager thinks search UI isn't visible when it should be", + searchManager.isVisible()); + } + + // Checks that the search UI is not visible. + // This checks both the SearchManager and the SearchManagerService, + // since SearchManager keeps a local variable for the visibility. + private void assertSearchNotVisible() { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertFalse("SearchManager thinks search UI is visible when it shouldn't be", + searchManager.isVisible()); } /** @@ -97,9 +122,7 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase2<LocalAct */ @MediumTest public void testSearchManagerInterfaceAvailable() { - ISearchManager searchManager1 = ISearchManager.Stub.asInterface( - ServiceManager.getService(Context.SEARCH_SERVICE)); - assertNotNull(searchManager1); + assertNotNull(getSearchManagerService()); } /** @@ -135,38 +158,127 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase2<LocalAct SearchManager searchManager2 = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); assertNotNull(searchManager2); - assertSame( searchManager1, searchManager2 ); + assertSame(searchManager1, searchManager2 ); } - + + @MediumTest + public void testSearchables() { + SearchableInfo si; + + si = SearchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, false); + assertNotNull(si); + assertFalse(SearchManager.isDefaultSearchable(si)); + si = SearchManager.getSearchableInfo(SEARCHABLE_ACTIVITY, true); + assertNotNull(si); + assertTrue(SearchManager.isDefaultSearchable(si)); + si = SearchManager.getSearchableInfo(null, true); + assertNotNull(si); + assertTrue(SearchManager.isDefaultSearchable(si)); + } + + /** + * Tests that rapid calls to start-stop-start doesn't cause problems. + */ + @MediumTest + public void testSearchManagerFastInvocations() throws Exception { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager); + assertSearchNotVisible(); + + searchManager.startSearch(null, false, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + searchManager.startSearch(null, false, SEARCHABLE_ACTIVITY, null, false); + searchManager.stopSearch(); + assertSearchNotVisible(); + } + + /** + * Tests that startSearch() is idempotent. + */ + @MediumTest + public void testStartSearchIdempotent() throws Exception { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager); + assertSearchNotVisible(); + + searchManager.startSearch(null, false, SEARCHABLE_ACTIVITY, null, false); + searchManager.startSearch(null, false, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + assertSearchNotVisible(); + } + + /** + * Tests that stopSearch() is idempotent and can be called when the search UI is not visible. + */ + @MediumTest + public void testStopSearchIdempotent() throws Exception { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager); + assertSearchNotVisible(); + searchManager.stopSearch(); + assertSearchNotVisible(); + + searchManager.startSearch(null, false, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + searchManager.stopSearch(); + assertSearchNotVisible(); + } + /** * The goal of this test is to confirm that we can start and then * stop a simple search. */ - - @MediumTest - public void testSearchManagerInvocations() { + @MediumTest + public void testSearchManagerInvocations() throws Exception { SearchManager searchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); assertNotNull(searchManager); - - // TODO: make a real component name, or remove this need - final ComponentName cn = new ComponentName("", ""); - - if (TEST_SEARCH_START != 0) { - // These tests should simply run to completion w/o exceptions - searchManager.startSearch(null, false, cn, null, false); - searchManager.stopSearch(); - - searchManager.startSearch("", false, cn, null, false); - searchManager.stopSearch(); - - searchManager.startSearch("test search string", false, cn, null, false); - searchManager.stopSearch(); - - searchManager.startSearch("test search string", true, cn, null, false); - searchManager.stopSearch(); - } - } + assertSearchNotVisible(); -} + // These tests should simply run to completion w/o exceptions + searchManager.startSearch(null, false, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + assertSearchNotVisible(); + + searchManager.startSearch("", false, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + assertSearchNotVisible(); + + searchManager.startSearch("test search string", false, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + assertSearchNotVisible(); + + searchManager.startSearch("test search string", true, SEARCHABLE_ACTIVITY, null, false); + assertSearchVisible(); + searchManager.stopSearch(); + assertSearchNotVisible(); + } + @MediumTest + public void testSearchDialogState() throws Exception { + SearchManager searchManager = (SearchManager) + mContext.getSystemService(Context.SEARCH_SERVICE); + assertNotNull(searchManager); + + Bundle searchState; + + // search dialog not visible, so no state should be stored + searchState = searchManager.saveSearchDialog(); + assertNull(searchState); + + searchManager.startSearch("test search string", true, SEARCHABLE_ACTIVITY, null, false); + searchState = searchManager.saveSearchDialog(); + assertNotNull(searchState); + searchManager.stopSearch(); + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchableActivity.java b/tests/AndroidTests/src/com/android/unit_tests/SearchableActivity.java new file mode 100644 index 0000000..53f40e9 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SearchableActivity.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.unit_tests; + +import android.app.Activity; +import android.os.Bundle; + +public class SearchableActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + finish(); + } + +} diff --git a/tests/AndroidTests/src/com/android/unit_tests/SuggestionProvider.java b/tests/AndroidTests/src/com/android/unit_tests/SuggestionProvider.java new file mode 100644 index 0000000..bc61e27 --- /dev/null +++ b/tests/AndroidTests/src/com/android/unit_tests/SuggestionProvider.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.unit_tests; + +import android.app.SearchManager; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Intent; +import android.content.UriMatcher; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.net.Uri; + +/** Simple test provider that runs in the local process. + * + * Used by {@link SearchManagerTest}. + */ +public class SuggestionProvider extends ContentProvider { + private static final String TAG = "SuggestionProvider"; + + private static final int SEARCH_SUGGESTIONS = 1; + + private static final UriMatcher sURLMatcher = new UriMatcher( + UriMatcher.NO_MATCH); + + static { + sURLMatcher.addURI("*", SearchManager.SUGGEST_URI_PATH_QUERY, + SEARCH_SUGGESTIONS); + sURLMatcher.addURI("*", SearchManager.SUGGEST_URI_PATH_QUERY + "/*", + SEARCH_SUGGESTIONS); + } + + private static final String[] COLUMNS = new String[] { + "_id", + SearchManager.SUGGEST_COLUMN_TEXT_1, + SearchManager.SUGGEST_COLUMN_INTENT_ACTION, + SearchManager.SUGGEST_COLUMN_QUERY + }; + + public SuggestionProvider() { + } + + @Override + public boolean onCreate() { + return true; + } + + @Override + public Cursor query(Uri url, String[] projectionIn, String selection, + String[] selectionArgs, String sort) { + int match = sURLMatcher.match(url); + switch (match) { + case SEARCH_SUGGESTIONS: + String query = url.getLastPathSegment(); + MatrixCursor cursor = new MatrixCursor(COLUMNS); + String[] suffixes = { "", "a", " foo", "XXXXXXXXXXXXXXXXX" }; + for (String suffix : suffixes) { + addRow(cursor, query + suffix); + } + return cursor; + default: + throw new IllegalArgumentException("Unknown URL: " + url); + } + } + + private void addRow(MatrixCursor cursor, String string) { + long id = cursor.getCount(); + cursor.newRow().add(id).add(string).add(Intent.ACTION_SEARCH).add(string); + } + + @Override + public String getType(Uri url) { + int match = sURLMatcher.match(url); + switch (match) { + case SEARCH_SUGGESTIONS: + return SearchManager.SUGGEST_MIME_TYPE; + default: + throw new IllegalArgumentException("Unknown URL: " + url); + } + } + + @Override + public int update(Uri url, ContentValues values, String where, String[] whereArgs) { + throw new UnsupportedOperationException("update not supported"); + } + + @Override + public Uri insert(Uri url, ContentValues initialValues) { + throw new UnsupportedOperationException("insert not supported"); + } + + @Override + public int delete(Uri url, String where, String[] whereArgs) { + throw new UnsupportedOperationException("delete not supported"); + } +} |
