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.tv.search; 18 19 import android.app.SearchManager; 20 import android.content.ContentProvider; 21 import android.content.ContentValues; 22 import android.database.Cursor; 23 import android.database.MatrixCursor; 24 import android.net.Uri; 25 import android.text.TextUtils; 26 import android.util.Log; 27 28 import com.android.tv.util.PermissionUtils; 29 30 import java.util.ArrayList; 31 import java.util.Arrays; 32 import java.util.List; 33 34 public class LocalSearchProvider extends ContentProvider { 35 private static final boolean DEBUG = false; 36 private static final String TAG = "LocalSearchProvider"; 37 38 public static final int PROGRESS_PERCENTAGE_HIDE = -1; 39 40 // TODO: Remove this once added to the SearchManager. 41 private static final String SUGGEST_COLUMN_PROGRESS_BAR_PERCENTAGE = "progress_bar_percentage"; 42 43 private static final String[] SEARCHABLE_COLUMNS = new String[] { 44 SearchManager.SUGGEST_COLUMN_TEXT_1, 45 SearchManager.SUGGEST_COLUMN_TEXT_2, 46 SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE, 47 SearchManager.SUGGEST_COLUMN_INTENT_ACTION, 48 SearchManager.SUGGEST_COLUMN_INTENT_DATA, 49 SearchManager.SUGGEST_COLUMN_CONTENT_TYPE, 50 SearchManager.SUGGEST_COLUMN_IS_LIVE, 51 SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH, 52 SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT, 53 SearchManager.SUGGEST_COLUMN_DURATION, 54 SUGGEST_COLUMN_PROGRESS_BAR_PERCENTAGE 55 }; 56 57 private static final String EXPECTED_PATH_PREFIX = "/" + SearchManager.SUGGEST_URI_PATH_QUERY; 58 // The launcher passes 10 as a 'limit' parameter by default. 59 private static final int DEFAULT_SEARCH_LIMIT = 10; 60 61 private static final String NO_LIVE_CONTENTS = "0"; 62 private static final String LIVE_CONTENTS = "1"; 63 64 static final String SUGGEST_PARAMETER_ACTION = "action"; 65 static final int DEFAULT_SEARCH_ACTION = SearchInterface.ACTION_TYPE_AMBIGUOUS; 66 67 @Override onCreate()68 public boolean onCreate() { 69 return true; 70 } 71 72 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)73 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 74 String sortOrder) { 75 if (DEBUG) { 76 Log.d(TAG, "query(" + uri + ", " + Arrays.toString(projection) + ", " + selection + ", " 77 + Arrays.toString(selectionArgs) + ", " + sortOrder + ")"); 78 } 79 SearchInterface search; 80 if (PermissionUtils.hasAccessAllEpg(getContext())) { 81 search = new TvProviderSearch(getContext()); 82 } else { 83 search = new DataManagerSearch(getContext()); 84 } 85 String query = uri.getLastPathSegment(); 86 int limit = DEFAULT_SEARCH_LIMIT; 87 int action = DEFAULT_SEARCH_ACTION; 88 try { 89 limit = Integer.parseInt(uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT)); 90 action = Integer.parseInt(uri.getQueryParameter(SUGGEST_PARAMETER_ACTION)); 91 } catch (NumberFormatException | UnsupportedOperationException e) { 92 // Ignore the exceptions 93 } 94 List<SearchResult> results = new ArrayList<>(); 95 if (!TextUtils.isEmpty(query)) { 96 results.addAll(search.search(query, limit, action)); 97 } 98 return createSuggestionsCursor(results); 99 } 100 createSuggestionsCursor(List<SearchResult> results)101 private Cursor createSuggestionsCursor(List<SearchResult> results) { 102 MatrixCursor cursor = new MatrixCursor(SEARCHABLE_COLUMNS, results.size()); 103 List<String> row = new ArrayList<>(SEARCHABLE_COLUMNS.length); 104 105 for (SearchResult result : results) { 106 row.clear(); 107 row.add(result.title); 108 row.add(result.description); 109 row.add(result.imageUri); 110 row.add(result.intentAction); 111 row.add(result.intentData); 112 row.add(result.contentType); 113 row.add(result.isLive ? LIVE_CONTENTS : NO_LIVE_CONTENTS); 114 row.add(result.videoWidth == 0 ? null : String.valueOf(result.videoWidth)); 115 row.add(result.videoHeight == 0 ? null : String.valueOf(result.videoHeight)); 116 row.add(result.duration == 0 ? null : String.valueOf(result.duration)); 117 row.add(String.valueOf(result.progressPercentage)); 118 cursor.addRow(row); 119 } 120 return cursor; 121 } 122 123 @Override getType(Uri uri)124 public String getType(Uri uri) { 125 if (!checkUriCorrect(uri)) return null; 126 return SearchManager.SUGGEST_MIME_TYPE; 127 } 128 checkUriCorrect(Uri uri)129 private static boolean checkUriCorrect(Uri uri) { 130 return uri != null && uri.getPath().startsWith(EXPECTED_PATH_PREFIX); 131 } 132 133 @Override insert(Uri uri, ContentValues values)134 public Uri insert(Uri uri, ContentValues values) { 135 throw new UnsupportedOperationException(); 136 } 137 138 @Override delete(Uri uri, String selection, String[] selectionArgs)139 public int delete(Uri uri, String selection, String[] selectionArgs) { 140 throw new UnsupportedOperationException(); 141 } 142 143 @Override update(Uri uri, ContentValues values, String selection, String[] selectionArgs)144 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 145 throw new UnsupportedOperationException(); 146 } 147 148 /** 149 * A placeholder to a search result. 150 */ 151 public static class SearchResult { 152 public long channelId; 153 public String channelNumber; 154 public String title; 155 public String description; 156 public String imageUri; 157 public String intentAction; 158 public String intentData; 159 public String contentType; 160 public boolean isLive; 161 public int videoWidth; 162 public int videoHeight; 163 public long duration; 164 public int progressPercentage; 165 166 @Override toString()167 public String toString() { 168 return "channelId: " + channelId + 169 ", channelNumber: " + channelNumber + 170 ", title: " + title; 171 } 172 } 173 }