relevent dictionary provider source code

This source code is a quick reference to the original code that is at google

http://developer.android.com/guide/samples/SearchableDictionary/index.html


/*
 * 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.
 */

/**
 * Provides search suggestions for a list of words and their definitions.
 */
public class DictionaryProvider extends ContentProvider {

    public static String AUTHORITY = "dictionary";

    private static final int SEARCH_SUGGEST = 0;
    private static final int SHORTCUT_REFRESH = 1;
    private static final UriMatcher sURIMatcher = buildUriMatcher();

    /**
     * The columns we'll include in our search suggestions.  There are others that could be used
     * to further customize the suggestions, see the docs in {@link SearchManager} for the details
     * on additional columns that are supported.
     */
    private static final String[] COLUMNS = {
            "_id",  // must include this column
            SearchManager.SUGGEST_COLUMN_TEXT_1,
            SearchManager.SUGGEST_COLUMN_TEXT_2,
            SearchManager.SUGGEST_COLUMN_INTENT_DATA,
            };


    /**
     * Sets up a uri matcher for search suggestion and shortcut refresh queries.
     */
    private static UriMatcher buildUriMatcher() {
        UriMatcher matcher =  new UriMatcher(UriMatcher.NO_MATCH);
        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT, SHORTCUT_REFRESH);
        matcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_SHORTCUT + "/*", SHORTCUT_REFRESH);
        return matcher;
    }

    @Override
    public boolean onCreate() {
        Resources resources = getContext().getResources();
        Dictionary.getInstance().ensureLoaded(resources);
        return true;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
            String sortOrder) {
        if (!TextUtils.isEmpty(selection)) {
            throw new IllegalArgumentException("selection not allowed for " + uri);
        }
        if (selectionArgs != null && selectionArgs.length != 0) {
            throw new IllegalArgumentException("selectionArgs not allowed for " + uri);
        }
        if (!TextUtils.isEmpty(sortOrder)) {
            throw new IllegalArgumentException("sortOrder not allowed for " + uri);
        }
        switch (sURIMatcher.match(uri)) {
            case SEARCH_SUGGEST:
                String query = null;
                if (uri.getPathSegments().size() > 1) {
                    query = uri.getLastPathSegment().toLowerCase();
                }
                return getSuggestions(query, projection);
            case SHORTCUT_REFRESH:
                String shortcutId = null;
                if (uri.getPathSegments().size() > 1) {
                    shortcutId = uri.getLastPathSegment();
                }
                return refreshShortcut(shortcutId, projection);
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
    }

    private Cursor getSuggestions(String query, String[] projection) {
        String processedQuery = query == null ? "" : query.toLowerCase();
        List<Dictionary.Word> words = Dictionary.getInstance().getMatches(processedQuery);

        MatrixCursor cursor = new MatrixCursor(COLUMNS);
        for (Dictionary.Word word : words) {
            cursor.addRow(columnValuesOfWord(word));
        }

        return cursor;
    }

    private Object[] columnValuesOfWord(Dictionary.Word word) {
        return new String[] {
                word.word,           // _id
                word.word,           // text1
                word.definition,     // text2
                word.word,           // intent_data (included when clicking on item)
        };
    }

    /**
     * Note: this is unused as is, but if we included
     * {@link SearchManager#SUGGEST_COLUMN_SHORTCUT_ID} as a column in our results, we
     * could expect to receive refresh queries on this uri for the id provided, in which case we
     * would return a cursor with a single item representing the refreshed suggestion data.
     */
    private Cursor refreshShortcut(String shortcutId, String[] projection) {
        return null;
    }

    /**
     * All queries for this provider are for the search suggestion and shortcut refresh mime type.
     */
    public String getType(Uri uri) {
        switch (sURIMatcher.match(uri)) {
            case SEARCH_SUGGEST:
                return SearchManager.SUGGEST_MIME_TYPE;
            case SHORTCUT_REFRESH:
                return SearchManager.SHORTCUT_MIME_TYPE;
            default:
                throw new IllegalArgumentException("Unknown URL " + uri);
        }
    }

    public Uri insert(Uri uri, ContentValues values) {
        throw new UnsupportedOperationException();
    }

    public int delete(Uri uri, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException();
    }

    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
        throw new UnsupportedOperationException();
    }
}

/**
 * The main activity for the dictionary.  Also displays search results triggered by the search
 * dialog.
 */
public class SearchableDictionary extends Activity {

    private static final int MENU_SEARCH = 1;

    private TextView mTextView;
    private ListView mList;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();

        setContentView(R.layout.main);
        mTextView = (TextView) findViewById(R.id.textField);
        mList = (ListView) findViewById(R.id.list);

        if (Intent.ACTION_VIEW.equals(intent.getAction())) {
            // from click on search results
            Dictionary.getInstance().ensureLoaded(getResources());
            String word = intent.getDataString();
            Dictionary.Word theWord = Dictionary.getInstance().getMatches(word).get(0);
            launchWord(theWord);
            finish();
        } else if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
            String query = intent.getStringExtra(SearchManager.QUERY);
            mTextView.setText(getString(R.string.search_results, query));
            WordAdapter wordAdapter = new WordAdapter(Dictionary.getInstance().getMatches(query));
            mList.setAdapter(wordAdapter);
            mList.setOnItemClickListener(wordAdapter);
        }

        Log.d("dict", intent.toString());
        if (intent.getExtras() != null) {
            Log.d("dict", intent.getExtras().keySet().toString());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0, MENU_SEARCH, 0, R.string.menu_search)
                .setIcon(android.R.drawable.ic_search_category_default)
                .setAlphabeticShortcut(SearchManager.MENU_KEY);

        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case MENU_SEARCH:
                onSearchRequested();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void launchWord(Dictionary.Word theWord) {
        Intent next = new Intent();
        next.setClass(this, WordActivity.class);
        next.putExtra("word", theWord.word);
        next.putExtra("definition", theWord.definition);
        startActivity(next);
    }

    class WordAdapter extends BaseAdapter implements AdapterView.OnItemClickListener {

        private final List<Dictionary.Word> mWords;
        private final LayoutInflater mInflater;

        public WordAdapter(List<Dictionary.Word> words) {
            mWords = words;
            mInflater = (LayoutInflater) SearchableDictionary.this.getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
        }

        public int getCount() {
            return mWords.size();
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            TwoLineListItem view = (convertView != null) ? (TwoLineListItem) convertView :
                    createView(parent);
            bindView(view, mWords.get(position));
            return view;
        }

        private TwoLineListItem createView(ViewGroup parent) {
            TwoLineListItem item = (TwoLineListItem) mInflater.inflate(
                    android.R.layout.simple_list_item_2, parent, false);
            item.getText2().setSingleLine();
            item.getText2().setEllipsize(TextUtils.TruncateAt.END);
            return item;
        }

        private void bindView(TwoLineListItem view, Dictionary.Word word) {
            view.getText1().setText(word.word);
            view.getText2().setText(word.definition);
        }

        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            launchWord(mWords.get(position));
        }
    }
}

/**
 * Contains logic to load the word of words and definitions and find a list of matching words
 * given a query.  Everything is held in memory; this is not a robust way to serve lots of
 * words and is only for demo purposes.
 *
 * You may want to consider using an SQLite database. In practice, you'll want to make sure your
 * suggestion provider is as efficient as possible, as the system will be taxed while performing
 * searches across many sources for each keystroke the user enters into Quick Search Box.
 */
public class Dictionary {

    public static class Word {
        public final String word;
        public final String definition;

        public Word(String word, String definition) {
            this.word = word;
            this.definition = definition;
        }
    }

    private static final Dictionary sInstance = new Dictionary();

    public static Dictionary getInstance() {
        return sInstance;
    }

    private final Map<String, List<Word>> mDict = new ConcurrentHashMap<String, List<Word>>();

    private Dictionary() {
    }

    private boolean mLoaded = false;

    /**
     * Loads the words and definitions if they haven't been loaded already.
     *
     * @param resources Used to load the file containing the words and definitions.
     */
    public synchronized void ensureLoaded(final Resources resources) {
        if (mLoaded) return;

        new Thread(new Runnable() {
            public void run() {
                try {
                    loadWords(resources);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }

    private synchronized void loadWords(Resources resources) throws IOException {
        if (mLoaded) return;

        Log.d("dict", "loading words");
        InputStream inputStream = resources.openRawResource(R.raw.definitions);
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        try {
            String line;
            while((line = reader.readLine()) != null) {
                String[] strings = TextUtils.split(line, "-");
                if (strings.length < 2) continue;
                addWord(strings[0].trim(), strings[1].trim());
            }
        } finally {
            reader.close();
        }
        mLoaded = true;
    }


    public List<Word> getMatches(String query) {
        List<Word> list = mDict.get(query);
        return list == null ? Collections.EMPTY_LIST : list;
    }

    private void addWord(String word, String definition) {
        final Word theWord = new Word(word, definition);

        final int len = word.length();
        for (int i = 0; i < len; i++) {
            final String prefix = word.substring(0, len - i);
            addMatch(prefix, theWord);
        }
    }

    private void addMatch(String query, Word word) {
        List<Word> matches = mDict.get(query);
        if (matches == null) {
            matches = new ArrayList<Word>();
            mDict.put(query, matches);
        }
        matches.add(word);
    }
}

/**
 * Displays a word and its definition.
 */
public class WordActivity extends Activity {

    private TextView mWord;
    private TextView mDefinition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.word);

        mWord = (TextView) findViewById(R.id.word);
        mDefinition = (TextView) findViewById(R.id.definition);

        Intent intent = getIntent();

        String word = intent.getStringExtra("word");
        String definition = intent.getStringExtra("definition");

        mWord.setText(word);
        mDefinition.setText(definition);
    }
}

<searchable xmlns:android="http://schemas.android.com/apk/res/android"
        android:label="@string/search_label"
        android:searchSettingsDescription="@string/settings_description"
        android:includeInGlobalSearch="true"
        android:searchSuggestAuthority="dictionary"
        android:searchSuggestIntentAction="android.intent.action.VIEW">
</searchable>