1 /* 2 * Copyright (C) 2015 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.tv; 18 19 import android.app.SearchManager; 20 import android.app.SearchableInfo; 21 import android.content.ContentProviderClient; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.pm.PackageManager; 26 import android.content.pm.ResolveInfo; 27 import android.database.Cursor; 28 import android.database.sqlite.SQLiteException; 29 import android.media.tv.TvContract; 30 import android.net.Uri; 31 import android.os.RemoteException; 32 import android.text.TextUtils; 33 34 import java.util.ArrayList; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Set; 38 39 /** 40 * A utility class for verifying channel/program results on global search requests. 41 */ 42 public class SearchUtil { SearchUtil()43 private SearchUtil() {} 44 45 /** 46 * Returns {@code true} if one of the search results matches the given {@code expectedResult}. 47 * 48 * @param context The context object to be used for getting content resolver 49 * @param searchable The {@link android.app.SearchableInfo} the TV app implements 50 * @param query A query string to search for 51 * @param expectedResult The expected search result 52 */ verifySearchResult(Context context, SearchableInfo searchable, String query, String expectedResult)53 public static boolean verifySearchResult(Context context, SearchableInfo searchable, 54 String query, String expectedResult) { 55 Uri.Builder uriBuilder = getSearchUri(searchable).buildUpon(); 56 String selection = searchable.getSuggestSelection(); 57 String[] selectionArg = null; 58 if (selection != null) { 59 selectionArg = new String[] { query }; 60 } else { 61 uriBuilder.appendPath(query); 62 } 63 64 Uri uri = uriBuilder.build(); 65 ContentProviderClient provider = context.getContentResolver() 66 .acquireUnstableContentProviderClient(uri); 67 try (Cursor c = provider.query(uri, null, selection, selectionArg, null, null)) { 68 while (c.moveToNext()) { 69 int index = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); 70 if (index >= 0) { 71 if (TextUtils.equals(expectedResult, c.getString(index))) { 72 return true; 73 } 74 } 75 } 76 } catch (SQLiteException | RemoteException e) { 77 return false; 78 } finally { 79 provider.release(); 80 } 81 return false; 82 } 83 84 /** 85 * Returns the {@link android.app.SearchableInfo} instances which should provide search results 86 * for channels and programs in TvProvider. 87 * 88 * @param context The context object to used for accessing system services 89 */ getSearchableInfos(Context context)90 public static List<SearchableInfo> getSearchableInfos(Context context) { 91 // Just in case EPG is provided by a separate package, collect all possible TV packages 92 // that can be searchable. 93 PackageManager pm = context.getPackageManager(); 94 Set<String> tvPackages = new HashSet<>(); 95 List<ResolveInfo> infos = pm.queryIntentActivities(new Intent(Intent.ACTION_VIEW, 96 TvContract.Channels.CONTENT_URI), 0); 97 for (ResolveInfo info : infos) { 98 tvPackages.add(info.activityInfo.packageName); 99 } 100 infos = pm.queryIntentActivities(new Intent(Intent.ACTION_VIEW, 101 TvContract.Programs.CONTENT_URI), 0); 102 for (ResolveInfo info : infos) { 103 tvPackages.add(info.activityInfo.packageName); 104 } 105 SearchManager sm = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); 106 List<SearchableInfo> globalSearchableInfos = sm.getSearchablesInGlobalSearch(); 107 List<SearchableInfo> tvSearchableInfos = new ArrayList<>(); 108 for (SearchableInfo info : globalSearchableInfos) { 109 if (tvPackages.contains(info.getSearchActivity().getPackageName())) { 110 tvSearchableInfos.add(info); 111 } 112 } 113 return tvSearchableInfos; 114 } 115 getSearchUri(SearchableInfo searchable)116 private static Uri getSearchUri(SearchableInfo searchable) { 117 if (searchable == null) { 118 return null; 119 } 120 String authority = searchable.getSuggestAuthority(); 121 if (authority == null) { 122 return null; 123 } 124 Uri.Builder uriBuilder = new Uri.Builder() 125 .scheme(ContentResolver.SCHEME_CONTENT) 126 .authority(authority); 127 128 final String contentPath = searchable.getSuggestPath(); 129 if (contentPath != null) { 130 uriBuilder.appendEncodedPath(contentPath); 131 } 132 133 uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); 134 return uriBuilder.build(); 135 } 136 } 137