102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert/* 202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * Copyright (C) 2009 The Android Open Source Project 302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * 402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * Licensed under the Apache License, Version 2.0 (the "License"); 502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * you may not use this file except in compliance with the License. 602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * You may obtain a copy of the License at 702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * 802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * http://www.apache.org/licenses/LICENSE-2.0 902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * 1002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * Unless required by applicable law or agreed to in writing, software 1102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * distributed under the License is distributed on an "AS IS" BASIS, 1202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * See the License for the specific language governing permissions and 1402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * limitations under the License. 1502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert */ 1602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 1702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertpackage com.android.quicksearchbox.benchmarks; 1802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 1902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.app.Activity; 2002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.app.SearchManager; 2102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.app.SearchableInfo; 2202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.content.ComponentName; 2302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.content.ContentResolver; 2402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.database.ContentObserver; 2502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.database.Cursor; 2602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.database.DataSetObserver; 2702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.net.Uri; 2802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.os.Bundle; 2902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.os.Handler; 3002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.os.Looper; 3102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport android.util.Log; 3202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 3302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport java.util.concurrent.ExecutorService; 3402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertimport java.util.concurrent.Executors; 3502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 3602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringertpublic abstract class SourceLatency extends Activity { 3702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 3802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private static final String TAG = "SourceLatency"; 3902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 4002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private SearchManager mSearchManager; 4102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 4202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private ExecutorService mExecutorService; 4302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 4402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 4502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert protected void onCreate(Bundle savedInstanceState) { 4602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert super.onCreate(savedInstanceState); 4702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 4802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mSearchManager = (SearchManager) getSystemService(SEARCH_SERVICE); 4902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mExecutorService = Executors.newSingleThreadExecutor(); 5002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 5102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 5202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 5302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert protected void onResume() { 5402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert super.onResume(); 5502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 5602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // TODO: call finish() when all tasks are done 5702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 5802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 5902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private SearchableInfo getSearchable(ComponentName componentName) { 6002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert SearchableInfo searchable = mSearchManager.getSearchableInfo(componentName); 6102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (searchable == null || searchable.getSuggestAuthority() == null) { 6202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert throw new RuntimeException("Component is not searchable: " 6302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + componentName.flattenToShortString()); 6402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 6502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return searchable; 6602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 6702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 6802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert /** 6902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert * Keeps track of timings in nanoseconds. 7002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert */ 7102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private static class ElapsedTime { 7202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private long mTotal = 0; 7302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private int mCount = 0; 7402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public synchronized void addTime(long time) { 7502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mTotal += time; 7602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mCount++; 7702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 7802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public synchronized long getTotal() { 7902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return mTotal; 8002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 8102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public synchronized long getAverage() { 8202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return mTotal / mCount; 8302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 8402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public synchronized int getCount() { 8502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return mCount; 8602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 8702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 8802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 8902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void checkSourceConcurrent(final String src, final ComponentName componentName, 9002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert String query, long delay) { 9102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert final ElapsedTime time = new ElapsedTime(); 9202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert final SearchableInfo searchable = getSearchable(componentName); 9302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert int length = query.length(); 9402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert for (int end = 0; end <= length; end++) { 9502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert final String prefix = query.substring(0, end); 9602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert (new Thread() { 9702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 9802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void run() { 9902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long t = checkSourceInternal(src, searchable, prefix); 10002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert time.addTime(t); 10102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 10202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert }).start(); 10302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert try { 10402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Thread.sleep(delay); 10502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } catch (InterruptedException ex) { 10602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.e(TAG, "sleep() in checkSourceConcurrent() interrupted."); 10702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 10802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 10902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert int count = length + 1; 11002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // wait for all requests to finish 11102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert while (time.getCount() < count) { 11202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert try { 11302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Thread.sleep(1000); 11402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } catch (InterruptedException ex) { 11502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.e(TAG, "sleep() in checkSourceConcurrent() interrupted."); 11602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 11702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 11802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, src + "[DONE]: " + length + " queries in " + formatTime(time.getAverage()) 11902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " (average), " + formatTime(time.getTotal()) + " (total)"); 12002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 12102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 12202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void checkSource(String src, ComponentName componentName, String[] queries) { 12302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert ElapsedTime time = new ElapsedTime(); 12402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert int count = queries.length; 12502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert for (int i = 0; i < queries.length; i++) { 12602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long t = checkSource(src, componentName, queries[i]); 12702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert time.addTime(t); 12802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 12902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, src + "[DONE]: " + count + " queries in " + formatTime(time.getAverage()) 13002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " (average), " + formatTime(time.getTotal()) + " (total)"); 13102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 13202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 13302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public long checkSource(String src, ComponentName componentName, String query) { 13402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert SearchableInfo searchable = getSearchable(componentName); 13502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return checkSourceInternal(src, searchable, query); 13602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 13702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 13802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private long checkSourceInternal(String src, SearchableInfo searchable, String query) { 13902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Cursor cursor = null; 14002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert try { 14102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert final long start = System.nanoTime(); 14202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert cursor = getSuggestions(searchable, query); 14302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long end = System.nanoTime(); 14402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long elapsed = end - start; 14502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (cursor == null) { 14602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, src + ": null cursor in " + formatTime(elapsed) 14702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " for '" + query + "'"); 14802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } else { 14902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, src + ": " + cursor.getCount() + " rows in " + formatTime(elapsed) 15002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " for '" + query + "'"); 15102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 15202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return elapsed; 15302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } finally { 15402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (cursor != null) { 15502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert cursor.close(); 15602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 15702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 15802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 15902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 16002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public Cursor getSuggestions(SearchableInfo searchable, String query) { 16102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return getSuggestions(searchable, query, -1); 16202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 16302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 16402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public Cursor getSuggestions(SearchableInfo searchable, String query, int limit) { 16502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (searchable == null) { 16602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return null; 16702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 16802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 16902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert String authority = searchable.getSuggestAuthority(); 17002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (authority == null) { 17102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return null; 17202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 17302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 17402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Uri.Builder uriBuilder = new Uri.Builder() 17502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert .scheme(ContentResolver.SCHEME_CONTENT) 17602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert .authority(authority) 17702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert .query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel() 17802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert .fragment(""); // TODO: Remove, workaround for a bug in Uri.writeToParcel() 17902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 18002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // if content path provided, insert it now 18102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert final String contentPath = searchable.getSuggestPath(); 18202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (contentPath != null) { 18302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert uriBuilder.appendEncodedPath(contentPath); 18402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 18502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 18602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // append standard suggestion query path 18702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY); 18802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 18902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // get the query selection, may be null 19002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert String selection = searchable.getSuggestSelection(); 19102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // inject query, either as selection args or inline 19202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert String[] selArgs = null; 19302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (selection != null) { // use selection if provided 19402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert selArgs = new String[] { query }; 19502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } else { // no selection, use REST pattern 19602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert uriBuilder.appendPath(query); 19702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 19802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 19902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (limit > 0) { 20002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert uriBuilder.appendQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT, 20102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert String.valueOf(limit)); 20202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 20302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 20402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Uri uri = uriBuilder.build(); 20502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 20602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert // finally, make the query 20702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return getContentResolver().query(uri, null, selection, selArgs, null); 20802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 20902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 21002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private static String formatTime(long ns) { 21102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return (ns / 1000000.0d) + " ms"; 21202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 21302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 21402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void checkLiveSource(String src, ComponentName componentName, String query) { 21502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mExecutorService.submit(new LiveSourceCheck(src, componentName, query)); 21602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 21702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 21802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private class LiveSourceCheck implements Runnable { 21902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 22002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private String mSrc; 22102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private SearchableInfo mSearchable; 22202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private String mQuery; 22302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private Handler mHandler = new Handler(Looper.getMainLooper()); 22402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 22502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public LiveSourceCheck(String src, ComponentName componentName, String query) { 22602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mSrc = src; 22702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mSearchable = mSearchManager.getSearchableInfo(componentName); 22802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert assert(mSearchable != null); 22902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert assert(mSearchable.getSuggestAuthority() != null); 23002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mQuery = query; 23102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 23202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 23302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void run() { 23402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Cursor cursor = null; 23502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert try { 23602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert final long start = System.nanoTime(); 23702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert cursor = getSuggestions(mSearchable, mQuery); 23802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long end = System.nanoTime(); 23902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long elapsed = (end - start); 24002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (cursor == null) { 24102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, mSrc + ": null cursor in " + formatTime(elapsed) 24202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " for '" + mQuery + "'"); 24302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } else { 24402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, mSrc + ": " + cursor.getCount() + " rows in " + formatTime(elapsed) 24502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " for '" + mQuery + "'"); 24602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert cursor.registerContentObserver(new ChangeObserver(cursor)); 24702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert cursor.registerDataSetObserver(new MyDataSetObserver(mSrc, start, cursor)); 24802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert try { 24902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Thread.sleep(2000); 25002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } catch (InterruptedException ex) { 25102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, mSrc + ": interrupted"); 25202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 25302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 25402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } finally { 25502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert if (cursor != null) { 25602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert cursor.close(); 25702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 25802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 25902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 26002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 26102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private class ChangeObserver extends ContentObserver { 26202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private Cursor mCursor; 26302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 26402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public ChangeObserver(Cursor cursor) { 26502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert super(mHandler); 26602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mCursor = cursor; 26702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 26802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 26902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 27002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public boolean deliverSelfNotifications() { 27102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert return true; 27202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 27302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 27402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 27502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void onChange(boolean selfChange) { 27602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mCursor.requery(); 27702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 27802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 27902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 28002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private class MyDataSetObserver extends DataSetObserver { 28102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private long mStart; 28202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private Cursor mCursor; 28302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert private int mUpdateCount = 0; 28402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 28502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public MyDataSetObserver(String src, long start, Cursor cursor) { 28602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mSrc = src; 28702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mStart = start; 28802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mCursor = cursor; 28902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 29002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 29102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 29202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void onChanged() { 29302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long end = System.nanoTime(); 29402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert long elapsed = end - mStart; 29502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert mUpdateCount++; 29602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, mSrc + ", update " + mUpdateCount + ": " + mCursor.getCount() 29702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert + " rows in " + formatTime(elapsed)); 29802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 29902d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 30002d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert @Override 30102d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert public void onInvalidated() { 30202d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert Log.d(TAG, mSrc + ": invalidated"); 30302d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 30402d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 30502d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert } 30602d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 30702d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert 30802d897ec26d81fa1f3cb9e1b8f05c6bcb5d7b9dbBjorn Bringert} 309