164c64e7c25e6efe31fa53369ec49db442b68ff9amah/*
264c64e7c25e6efe31fa53369ec49db442b68ff9amah * Copyright (C) 2010 The Android Open Source Project
364c64e7c25e6efe31fa53369ec49db442b68ff9amah *
464c64e7c25e6efe31fa53369ec49db442b68ff9amah * Licensed under the Apache License, Version 2.0 (the "License");
564c64e7c25e6efe31fa53369ec49db442b68ff9amah * you may not use this file except in compliance with the License.
664c64e7c25e6efe31fa53369ec49db442b68ff9amah * You may obtain a copy of the License at
764c64e7c25e6efe31fa53369ec49db442b68ff9amah *
864c64e7c25e6efe31fa53369ec49db442b68ff9amah *      http://www.apache.org/licenses/LICENSE-2.0
964c64e7c25e6efe31fa53369ec49db442b68ff9amah *
1064c64e7c25e6efe31fa53369ec49db442b68ff9amah * Unless required by applicable law or agreed to in writing, software
1164c64e7c25e6efe31fa53369ec49db442b68ff9amah * distributed under the License is distributed on an "AS IS" BASIS,
1264c64e7c25e6efe31fa53369ec49db442b68ff9amah * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1364c64e7c25e6efe31fa53369ec49db442b68ff9amah * See the License for the specific language governing permissions and
1464c64e7c25e6efe31fa53369ec49db442b68ff9amah * limitations under the License.
1564c64e7c25e6efe31fa53369ec49db442b68ff9amah */
1664c64e7c25e6efe31fa53369ec49db442b68ff9amahpackage com.android.voicedialer;
1764c64e7c25e6efe31fa53369ec49db442b68ff9amah
1864c64e7c25e6efe31fa53369ec49db442b68ff9amah
1964c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.content.ContentUris;
2064c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.content.Context;
2164c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.content.Intent;
2264c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.content.pm.PackageManager;
2364c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.content.pm.ResolveInfo;
2464c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.content.res.Resources;
2564c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.net.Uri;
2664c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.provider.ContactsContract.CommonDataKinds.Phone;
2764c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.speech.srec.Recognizer;
2864c64e7c25e6efe31fa53369ec49db442b68ff9amahimport android.util.Log;
2985a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa
3064c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.File;
3164c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.FileFilter;
3264c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.FileInputStream;
3364c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.FileOutputStream;
3464c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.IOException;
3564c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.ObjectInputStream;
3664c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.io.ObjectOutputStream;
3764c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.net.URISyntaxException;
3864c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.util.ArrayList;
3964c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.util.HashMap;
4064c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.util.HashSet;
4164c64e7c25e6efe31fa53369ec49db442b68ff9amahimport java.util.List;
4264c64e7c25e6efe31fa53369ec49db442b68ff9amah/**
4364c64e7c25e6efe31fa53369ec49db442b68ff9amah * This is a RecognizerEngine that processes commands to make phone calls and
4464c64e7c25e6efe31fa53369ec49db442b68ff9amah * open applications.
4564c64e7c25e6efe31fa53369ec49db442b68ff9amah * <ul>
467a55150b308ed03d41091e4c3ac693d6eb0ab145mah * <li>setupGrammar
4764c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>Scans contacts and determine if the Grammar g2g file is stale.
4864c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>If so, create and rebuild the Grammar,
4964c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>Else create and load the Grammar from the file.
5064c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>onRecognitionSuccess is called when we get results from the recognizer,
5164c64e7c25e6efe31fa53369ec49db442b68ff9amah * it will process the results, which will pass a list of intents to
5264c64e7c25e6efe31fa53369ec49db442b68ff9amah * the {@RecognizerClient}.  It will accept the following types of commands:
5364c64e7c25e6efe31fa53369ec49db442b68ff9amah * "call" a particular contact
5464c64e7c25e6efe31fa53369ec49db442b68ff9amah * "dial a particular number
5564c64e7c25e6efe31fa53369ec49db442b68ff9amah * "open" a particular application
5664c64e7c25e6efe31fa53369ec49db442b68ff9amah * "redial" the last number called
5764c64e7c25e6efe31fa53369ec49db442b68ff9amah * "voicemail" to call voicemail
5864c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>Pass a list of {@link Intent} corresponding to the recognition results
5964c64e7c25e6efe31fa53369ec49db442b68ff9amah * to the {@link RecognizerClient}, which notifies the user.
6064c64e7c25e6efe31fa53369ec49db442b68ff9amah * </ul>
6164c64e7c25e6efe31fa53369ec49db442b68ff9amah * Notes:
6264c64e7c25e6efe31fa53369ec49db442b68ff9amah * <ul>
6364c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>Audio many be read from a file.
6464c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>A directory tree of audio files may be stepped through.
6564c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>A contact list may be read from a file.
6664c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>A {@link RecognizerLogger} may generate a set of log files from
6764c64e7c25e6efe31fa53369ec49db442b68ff9amah * a recognition session.
6864c64e7c25e6efe31fa53369ec49db442b68ff9amah * <li>A static instance of this class is held and reused by the
6964c64e7c25e6efe31fa53369ec49db442b68ff9amah * {@link VoiceDialerActivity}, which saves setup time.
7064c64e7c25e6efe31fa53369ec49db442b68ff9amah * </ul>
7164c64e7c25e6efe31fa53369ec49db442b68ff9amah */
7264c64e7c25e6efe31fa53369ec49db442b68ff9amahpublic class CommandRecognizerEngine extends RecognizerEngine {
7364c64e7c25e6efe31fa53369ec49db442b68ff9amah
7464c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static final String OPEN_ENTRIES = "openentries.txt";
757a55150b308ed03d41091e4c3ac693d6eb0ab145mah    public static final String PHONE_TYPE_EXTRA = "phone_type";
767a55150b308ed03d41091e4c3ac693d6eb0ab145mah    private static final int MINIMUM_CONFIDENCE = 100;
7764c64e7c25e6efe31fa53369ec49db442b68ff9amah    private File mContactsFile;
787a55150b308ed03d41091e4c3ac693d6eb0ab145mah    private boolean mMinimizeResults;
795f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon    private boolean mAllowOpenEntries;
804a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private HashMap<String,String> mOpenEntries;
815f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon
8264c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
8364c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Constructor.
8464c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
8564c64e7c25e6efe31fa53369ec49db442b68ff9amah    public CommandRecognizerEngine() {
867a55150b308ed03d41091e4c3ac693d6eb0ab145mah        mContactsFile = null;
877a55150b308ed03d41091e4c3ac693d6eb0ab145mah        mMinimizeResults = false;
885f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        mAllowOpenEntries = true;
8964c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
9064c64e7c25e6efe31fa53369ec49db442b68ff9amah
9164c64e7c25e6efe31fa53369ec49db442b68ff9amah    public void setContactsFile(File contactsFile) {
924a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        if (contactsFile != mContactsFile) {
934a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            mContactsFile = contactsFile;
944a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // if we change the contacts file, then we need to recreate the grammar.
954a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            if (mSrecGrammar != null) {
964a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mSrecGrammar.destroy();
974a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mSrecGrammar = null;
984a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mOpenEntries = null;
994a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            }
10064c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
10164c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
10264c64e7c25e6efe31fa53369ec49db442b68ff9amah
1037a55150b308ed03d41091e4c3ac693d6eb0ab145mah    public void setMinimizeResults(boolean minimizeResults) {
1047a55150b308ed03d41091e4c3ac693d6eb0ab145mah        mMinimizeResults = minimizeResults;
1057a55150b308ed03d41091e4c3ac693d6eb0ab145mah    }
1067a55150b308ed03d41091e4c3ac693d6eb0ab145mah
1075f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon    public void setAllowOpenEntries(boolean allowOpenEntries) {
1085f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        if (mAllowOpenEntries != allowOpenEntries) {
1095f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            // if we change this setting, then we need to recreate the grammar.
1105f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            if (mSrecGrammar != null) {
1115f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                mSrecGrammar.destroy();
1125f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                mSrecGrammar = null;
1134a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mOpenEntries = null;
1145f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            }
1155f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        }
1165f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        mAllowOpenEntries = allowOpenEntries;
1175f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon    }
1185f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon
11964c64e7c25e6efe31fa53369ec49db442b68ff9amah    protected void setupGrammar() throws IOException, InterruptedException {
12064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // fetch the contact list
121d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato        if (false) Log.d(TAG, "start getVoiceContacts");
122d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato        if (false) Log.d(TAG, "contactsFile is " + (mContactsFile == null ?
12364c64e7c25e6efe31fa53369ec49db442b68ff9amah            "null" : "not null"));
12464c64e7c25e6efe31fa53369ec49db442b68ff9amah        List<VoiceContact> contacts = mContactsFile != null ?
12564c64e7c25e6efe31fa53369ec49db442b68ff9amah                VoiceContact.getVoiceContactsFromFile(mContactsFile) :
12664c64e7c25e6efe31fa53369ec49db442b68ff9amah                VoiceContact.getVoiceContacts(mActivity);
12764c64e7c25e6efe31fa53369ec49db442b68ff9amah
12864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // log contacts if requested
12964c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (mLogger != null) mLogger.logContacts(contacts);
13064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // generate g2g grammar file name
13164c64e7c25e6efe31fa53369ec49db442b68ff9amah        File g2g = mActivity.getFileStreamPath("voicedialer." +
13264c64e7c25e6efe31fa53369ec49db442b68ff9amah                Integer.toHexString(contacts.hashCode()) + ".g2g");
13364c64e7c25e6efe31fa53369ec49db442b68ff9amah
13464c64e7c25e6efe31fa53369ec49db442b68ff9amah        // rebuild g2g file if current one is out of date
13564c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (!g2g.exists()) {
13664c64e7c25e6efe31fa53369ec49db442b68ff9amah            // clean up existing Grammar and old file
13764c64e7c25e6efe31fa53369ec49db442b68ff9amah            deleteAllG2GFiles(mActivity);
13864c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (mSrecGrammar != null) {
13964c64e7c25e6efe31fa53369ec49db442b68ff9amah                mSrecGrammar.destroy();
14064c64e7c25e6efe31fa53369ec49db442b68ff9amah                mSrecGrammar = null;
14164c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
14264c64e7c25e6efe31fa53369ec49db442b68ff9amah
14364c64e7c25e6efe31fa53369ec49db442b68ff9amah            // load the empty Grammar
144d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "start new Grammar");
14564c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar = mSrec.new Grammar(SREC_DIR + "/grammars/VoiceDialer.g2g");
14664c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar.setupRecognizer();
14764c64e7c25e6efe31fa53369ec49db442b68ff9amah
14864c64e7c25e6efe31fa53369ec49db442b68ff9amah            // reset slots
149d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "start grammar.resetAllSlots");
15064c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar.resetAllSlots();
15164c64e7c25e6efe31fa53369ec49db442b68ff9amah
15264c64e7c25e6efe31fa53369ec49db442b68ff9amah            // add names to the grammar
15364c64e7c25e6efe31fa53369ec49db442b68ff9amah            addNameEntriesToGrammar(contacts);
15464c64e7c25e6efe31fa53369ec49db442b68ff9amah
1555f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            if (mAllowOpenEntries) {
1565f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                // add open entries to the grammar
1575f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                addOpenEntriesToGrammar();
1585f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            }
15978d0235501ca19dd38e2ab12ed60c3fa86199fceMartin Hibdon
16064c64e7c25e6efe31fa53369ec49db442b68ff9amah            // compile the grammar
161d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "start grammar.compile");
16264c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar.compile();
16364c64e7c25e6efe31fa53369ec49db442b68ff9amah
16464c64e7c25e6efe31fa53369ec49db442b68ff9amah            // update g2g file
165d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "start grammar.save " + g2g.getPath());
16664c64e7c25e6efe31fa53369ec49db442b68ff9amah            g2g.getParentFile().mkdirs();
16764c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar.save(g2g.getPath());
16864c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
16964c64e7c25e6efe31fa53369ec49db442b68ff9amah
17064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // g2g file exists, but is not loaded
17164c64e7c25e6efe31fa53369ec49db442b68ff9amah        else if (mSrecGrammar == null) {
172d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "start new Grammar loading " + g2g);
17364c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar = mSrec.new Grammar(g2g.getPath());
17464c64e7c25e6efe31fa53369ec49db442b68ff9amah            mSrecGrammar.setupRecognizer();
17564c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
1764a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        if (mOpenEntries == null && mAllowOpenEntries) {
1774a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // make sure to load the openEntries mapping table.
1784a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            loadOpenEntriesTable();
1794a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        }
1804a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
18164c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
18264c64e7c25e6efe31fa53369ec49db442b68ff9amah
18364c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
18485a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa     * Number of phone ids appended to a grammer in {@link #addNameEntriesToGrammar(List)}.
18585a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa     */
18685a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa    private static final int PHONE_ID_COUNT = 7;
18785a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa
18885a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa    /**
18964c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Add a list of names to the grammar
19064c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param contacts list of VoiceContacts to be added.
19164c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
19264c64e7c25e6efe31fa53369ec49db442b68ff9amah    private void addNameEntriesToGrammar(List<VoiceContact> contacts)
19364c64e7c25e6efe31fa53369ec49db442b68ff9amah            throws InterruptedException {
194d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato        if (false) Log.d(TAG, "addNameEntriesToGrammar " + contacts.size());
19564c64e7c25e6efe31fa53369ec49db442b68ff9amah
19664c64e7c25e6efe31fa53369ec49db442b68ff9amah        HashSet<String> entries = new HashSet<String>();
19785a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa        StringBuilder sb = new StringBuilder();
19864c64e7c25e6efe31fa53369ec49db442b68ff9amah        int count = 0;
19964c64e7c25e6efe31fa53369ec49db442b68ff9amah        for (VoiceContact contact : contacts) {
20064c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Thread.interrupted()) throw new InterruptedException();
20164c64e7c25e6efe31fa53369ec49db442b68ff9amah            String name = scrubName(contact.mName);
20264c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (name.length() == 0 || !entries.add(name)) continue;
20364c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.setLength(0);
20485a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa            // The number of ids appended here must be same as PHONE_ID_COUNT.
20564c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append("V='");
20664c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append(contact.mContactId).append(' ');
20764c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append(contact.mPrimaryId).append(' ');
20864c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append(contact.mHomeId).append(' ');
20964c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append(contact.mMobileId).append(' ');
21064c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append(contact.mWorkId).append(' ');
21185a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa            sb.append(contact.mOtherId).append(' ');
21285a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa            sb.append(contact.mFallbackId);
21364c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.append("'");
21464c64e7c25e6efe31fa53369ec49db442b68ff9amah            try {
21564c64e7c25e6efe31fa53369ec49db442b68ff9amah                mSrecGrammar.addWordToSlot("@Names", name, null, 1, sb.toString());
21664c64e7c25e6efe31fa53369ec49db442b68ff9amah            } catch (Exception e) {
21764c64e7c25e6efe31fa53369ec49db442b68ff9amah                Log.e(TAG, "Cannot load all contacts to voice recognizer, loaded " +
21864c64e7c25e6efe31fa53369ec49db442b68ff9amah                        count, e);
21964c64e7c25e6efe31fa53369ec49db442b68ff9amah                break;
22064c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
22164c64e7c25e6efe31fa53369ec49db442b68ff9amah
22264c64e7c25e6efe31fa53369ec49db442b68ff9amah            count++;
22364c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
22464c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
22564c64e7c25e6efe31fa53369ec49db442b68ff9amah
22664c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
22764c64e7c25e6efe31fa53369ec49db442b68ff9amah     * add a list of application labels to the 'open x' grammar
22864c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
2294a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private void loadOpenEntriesTable() throws InterruptedException, IOException {
230d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato        if (false) Log.d(TAG, "addOpenEntriesToGrammar");
23164c64e7c25e6efe31fa53369ec49db442b68ff9amah
23264c64e7c25e6efe31fa53369ec49db442b68ff9amah        // fill this
23364c64e7c25e6efe31fa53369ec49db442b68ff9amah        File oe = mActivity.getFileStreamPath(OPEN_ENTRIES);
23464c64e7c25e6efe31fa53369ec49db442b68ff9amah
23564c64e7c25e6efe31fa53369ec49db442b68ff9amah        // build and write list of entries
23664c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (!oe.exists()) {
2374a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            mOpenEntries = new HashMap<String, String>();
23864c64e7c25e6efe31fa53369ec49db442b68ff9amah
23964c64e7c25e6efe31fa53369ec49db442b68ff9amah            // build a list of 'open' entries
24064c64e7c25e6efe31fa53369ec49db442b68ff9amah            PackageManager pm = mActivity.getPackageManager();
24164c64e7c25e6efe31fa53369ec49db442b68ff9amah            List<ResolveInfo> riList = pm.queryIntentActivities(
24264c64e7c25e6efe31fa53369ec49db442b68ff9amah                            new Intent(Intent.ACTION_MAIN).
24364c64e7c25e6efe31fa53369ec49db442b68ff9amah                            addCategory("android.intent.category.VOICE_LAUNCH"),
24464c64e7c25e6efe31fa53369ec49db442b68ff9amah                            PackageManager.GET_ACTIVITIES);
24564c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Thread.interrupted()) throw new InterruptedException();
24664c64e7c25e6efe31fa53369ec49db442b68ff9amah            riList.addAll(pm.queryIntentActivities(
24764c64e7c25e6efe31fa53369ec49db442b68ff9amah                            new Intent(Intent.ACTION_MAIN).
24864c64e7c25e6efe31fa53369ec49db442b68ff9amah                            addCategory("android.intent.category.LAUNCHER"),
24964c64e7c25e6efe31fa53369ec49db442b68ff9amah                            PackageManager.GET_ACTIVITIES));
25064c64e7c25e6efe31fa53369ec49db442b68ff9amah            String voiceDialerClassName = mActivity.getComponentName().getClassName();
25164c64e7c25e6efe31fa53369ec49db442b68ff9amah
25264c64e7c25e6efe31fa53369ec49db442b68ff9amah            // scan list, adding complete phrases, as well as individual words
25364c64e7c25e6efe31fa53369ec49db442b68ff9amah            for (ResolveInfo ri : riList) {
25464c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (Thread.interrupted()) throw new InterruptedException();
25564c64e7c25e6efe31fa53369ec49db442b68ff9amah
25664c64e7c25e6efe31fa53369ec49db442b68ff9amah                // skip self
25764c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (voiceDialerClassName.equals(ri.activityInfo.name)) continue;
25864c64e7c25e6efe31fa53369ec49db442b68ff9amah
25964c64e7c25e6efe31fa53369ec49db442b68ff9amah                // fetch a scrubbed window label
26064c64e7c25e6efe31fa53369ec49db442b68ff9amah                String label = scrubName(ri.loadLabel(pm).toString());
26164c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (label.length() == 0) continue;
26264c64e7c25e6efe31fa53369ec49db442b68ff9amah
26364c64e7c25e6efe31fa53369ec49db442b68ff9amah                // insert it into the result list
2644a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                addClassName(mOpenEntries, label,
26527d520022f552e3e4b17b00d6ec4db9306fe7deaMartin Hibdon                        ri.activityInfo.packageName, ri.activityInfo.name);
26664c64e7c25e6efe31fa53369ec49db442b68ff9amah
26764c64e7c25e6efe31fa53369ec49db442b68ff9amah                // split it into individual words, and insert them
26864c64e7c25e6efe31fa53369ec49db442b68ff9amah                String[] words = label.split(" ");
26964c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (words.length > 1) {
27064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    for (String word : words) {
27164c64e7c25e6efe31fa53369ec49db442b68ff9amah                        word = word.trim();
27264c64e7c25e6efe31fa53369ec49db442b68ff9amah                        // words must be three characters long, or two if capitalized
27364c64e7c25e6efe31fa53369ec49db442b68ff9amah                        int len = word.length();
27464c64e7c25e6efe31fa53369ec49db442b68ff9amah                        if (len <= 1) continue;
27564c64e7c25e6efe31fa53369ec49db442b68ff9amah                        if (len == 2 && !(Character.isUpperCase(word.charAt(0)) &&
27664c64e7c25e6efe31fa53369ec49db442b68ff9amah                                        Character.isUpperCase(word.charAt(1)))) continue;
27764c64e7c25e6efe31fa53369ec49db442b68ff9amah                        if ("and".equalsIgnoreCase(word) ||
27864c64e7c25e6efe31fa53369ec49db442b68ff9amah                                "the".equalsIgnoreCase(word)) continue;
27964c64e7c25e6efe31fa53369ec49db442b68ff9amah                        // add the word
2804a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        addClassName(mOpenEntries, word,
28127d520022f552e3e4b17b00d6ec4db9306fe7deaMartin Hibdon                                ri.activityInfo.packageName, ri.activityInfo.name);
28264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
28364c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
28464c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
28564c64e7c25e6efe31fa53369ec49db442b68ff9amah
28664c64e7c25e6efe31fa53369ec49db442b68ff9amah            // write list
287d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "addOpenEntriesToGrammar writing " + oe);
28864c64e7c25e6efe31fa53369ec49db442b68ff9amah            try {
28964c64e7c25e6efe31fa53369ec49db442b68ff9amah                 FileOutputStream fos = new FileOutputStream(oe);
29064c64e7c25e6efe31fa53369ec49db442b68ff9amah                 try {
29164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ObjectOutputStream oos = new ObjectOutputStream(fos);
2924a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    oos.writeObject(mOpenEntries);
29364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    oos.close();
29464c64e7c25e6efe31fa53369ec49db442b68ff9amah                } finally {
29564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    fos.close();
29664c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
29764c64e7c25e6efe31fa53369ec49db442b68ff9amah            } catch (IOException ioe) {
29864c64e7c25e6efe31fa53369ec49db442b68ff9amah                deleteCachedGrammarFiles(mActivity);
29964c64e7c25e6efe31fa53369ec49db442b68ff9amah                throw ioe;
30064c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
30164c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
30264c64e7c25e6efe31fa53369ec49db442b68ff9amah
30364c64e7c25e6efe31fa53369ec49db442b68ff9amah        // read the list
30464c64e7c25e6efe31fa53369ec49db442b68ff9amah        else {
305d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, "addOpenEntriesToGrammar reading " + oe);
30664c64e7c25e6efe31fa53369ec49db442b68ff9amah            try {
30764c64e7c25e6efe31fa53369ec49db442b68ff9amah                FileInputStream fis = new FileInputStream(oe);
30864c64e7c25e6efe31fa53369ec49db442b68ff9amah                try {
30964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ObjectInputStream ois = new ObjectInputStream(fis);
3104a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    mOpenEntries = (HashMap<String, String>)ois.readObject();
31164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ois.close();
31264c64e7c25e6efe31fa53369ec49db442b68ff9amah                } finally {
31364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    fis.close();
31464c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
31564c64e7c25e6efe31fa53369ec49db442b68ff9amah            } catch (Exception e) {
31664c64e7c25e6efe31fa53369ec49db442b68ff9amah                deleteCachedGrammarFiles(mActivity);
31764c64e7c25e6efe31fa53369ec49db442b68ff9amah                throw new IOException(e.toString());
31864c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
31964c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
3204a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    }
3214a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3224a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private void addOpenEntriesToGrammar() throws InterruptedException, IOException {
3234a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        // load up our open entries table
3244a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        loadOpenEntriesTable();
32564c64e7c25e6efe31fa53369ec49db442b68ff9amah
32664c64e7c25e6efe31fa53369ec49db442b68ff9amah        // add list of 'open' entries to the grammar
3274a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        for (String label : mOpenEntries.keySet()) {
32864c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Thread.interrupted()) throw new InterruptedException();
3294a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            String entry = mOpenEntries.get(label);
33064c64e7c25e6efe31fa53369ec49db442b68ff9amah            // don't add if too many results
33164c64e7c25e6efe31fa53369ec49db442b68ff9amah            int count = 0;
33264c64e7c25e6efe31fa53369ec49db442b68ff9amah            for (int i = 0; 0 != (i = entry.indexOf(' ', i) + 1); count++) ;
33364c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (count > RESULT_LIMIT) continue;
33464c64e7c25e6efe31fa53369ec49db442b68ff9amah            // add the word to the grammar
3354a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // See Bug: 2457238.
3364a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // We used to store the entire list of components into the grammar.
3374a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // Unfortuantely, the recognizer has a fixed limit on the length of
3384a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // the "semantic" string, which is easy to overflow.  So now,
3394a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // the we store our own mapping table between words and component
3404a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // names, and the entries in the grammar have the same value
3414a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // for literal and semantic.
3424a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            mSrecGrammar.addWordToSlot("@Opens", label, null, 1, "V='" + label + "'");
34364c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
34464c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
34564c64e7c25e6efe31fa53369ec49db442b68ff9amah
34664c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
34764c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Add a className to a hash table of class name lists.
34864c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param openEntries HashMap of lists of class names.
34964c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param label a label or word corresponding to the list of classes.
35064c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param className class name to add
35164c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
35264c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static void addClassName(HashMap<String,String> openEntries,
35327d520022f552e3e4b17b00d6ec4db9306fe7deaMartin Hibdon            String label, String packageName, String className) {
3544a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        String component = packageName + "/" + className;
35564c64e7c25e6efe31fa53369ec49db442b68ff9amah        String labelLowerCase = label.toLowerCase();
35664c64e7c25e6efe31fa53369ec49db442b68ff9amah        String classList = openEntries.get(labelLowerCase);
35764c64e7c25e6efe31fa53369ec49db442b68ff9amah
35864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // first item in the list
35964c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (classList == null) {
3604a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            openEntries.put(labelLowerCase, component);
36164c64e7c25e6efe31fa53369ec49db442b68ff9amah            return;
36264c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
36364c64e7c25e6efe31fa53369ec49db442b68ff9amah        // already in list
3644a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        int index = classList.indexOf(component);
3654a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        int after = index + component.length();
36664c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (index != -1 && (index == 0 || classList.charAt(index - 1) == ' ') &&
36764c64e7c25e6efe31fa53369ec49db442b68ff9amah                (after == classList.length() || classList.charAt(after) == ' ')) return;
36864c64e7c25e6efe31fa53369ec49db442b68ff9amah
36964c64e7c25e6efe31fa53369ec49db442b68ff9amah        // add it to the end
3704a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        openEntries.put(labelLowerCase, classList + ' ' + component);
37164c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
37264c64e7c25e6efe31fa53369ec49db442b68ff9amah
37364c64e7c25e6efe31fa53369ec49db442b68ff9amah    // map letters in Latin1 Supplement to basic ascii
37464c64e7c25e6efe31fa53369ec49db442b68ff9amah    // from http://en.wikipedia.org/wiki/Latin-1_Supplement_unicode_block
37564c64e7c25e6efe31fa53369ec49db442b68ff9amah    // not all letters map well, including Eth and Thorn
37664c64e7c25e6efe31fa53369ec49db442b68ff9amah    // TODO: this should really be all handled in the pronunciation engine
37764c64e7c25e6efe31fa53369ec49db442b68ff9amah    private final static char[] mLatin1Letters =
37864c64e7c25e6efe31fa53369ec49db442b68ff9amah            "AAAAAAACEEEEIIIIDNOOOOO OUUUUYDsaaaaaaaceeeeiiiidnooooo ouuuuydy".
37964c64e7c25e6efe31fa53369ec49db442b68ff9amah            toCharArray();
38064c64e7c25e6efe31fa53369ec49db442b68ff9amah    private final static int mLatin1Base = 0x00c0;
38164c64e7c25e6efe31fa53369ec49db442b68ff9amah
38264c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
38364c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Reformat a raw name from the contact list into a form a
38464c64e7c25e6efe31fa53369ec49db442b68ff9amah     * {@link Recognizer.Grammar} can digest.
38564c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param name the raw name.
38664c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @return the reformatted name.
38764c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
38864c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static String scrubName(String name) {
38964c64e7c25e6efe31fa53369ec49db442b68ff9amah        // replace '&' with ' and '
39064c64e7c25e6efe31fa53369ec49db442b68ff9amah        name = name.replace("&", " and ");
39164c64e7c25e6efe31fa53369ec49db442b68ff9amah
39264c64e7c25e6efe31fa53369ec49db442b68ff9amah        // replace '@' with ' at '
39364c64e7c25e6efe31fa53369ec49db442b68ff9amah        name = name.replace("@", " at ");
39464c64e7c25e6efe31fa53369ec49db442b68ff9amah
39564c64e7c25e6efe31fa53369ec49db442b68ff9amah        // remove '(...)'
39664c64e7c25e6efe31fa53369ec49db442b68ff9amah        while (true) {
39764c64e7c25e6efe31fa53369ec49db442b68ff9amah            int i = name.indexOf('(');
39864c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (i == -1) break;
39964c64e7c25e6efe31fa53369ec49db442b68ff9amah            int j = name.indexOf(')', i);
40064c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (j == -1) break;
40164c64e7c25e6efe31fa53369ec49db442b68ff9amah            name = name.substring(0, i) + " " + name.substring(j + 1);
40264c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
40364c64e7c25e6efe31fa53369ec49db442b68ff9amah
40464c64e7c25e6efe31fa53369ec49db442b68ff9amah        // map letters of Latin1 Supplement to basic ascii
40564c64e7c25e6efe31fa53369ec49db442b68ff9amah        char[] nm = null;
40664c64e7c25e6efe31fa53369ec49db442b68ff9amah        for (int i = name.length() - 1; i >= 0; i--) {
40764c64e7c25e6efe31fa53369ec49db442b68ff9amah            char ch = name.charAt(i);
40864c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (ch < ' ' || '~' < ch) {
40964c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (nm == null) nm = name.toCharArray();
41064c64e7c25e6efe31fa53369ec49db442b68ff9amah                nm[i] = mLatin1Base <= ch && ch < mLatin1Base + mLatin1Letters.length ?
41164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mLatin1Letters[ch - mLatin1Base] : ' ';
41264c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
41364c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
41464c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (nm != null) {
41564c64e7c25e6efe31fa53369ec49db442b68ff9amah            name = new String(nm);
41664c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
41764c64e7c25e6efe31fa53369ec49db442b68ff9amah
41864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // if '.' followed by alnum, replace with ' dot '
41964c64e7c25e6efe31fa53369ec49db442b68ff9amah        while (true) {
42064c64e7c25e6efe31fa53369ec49db442b68ff9amah            int i = name.indexOf('.');
42164c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (i == -1 ||
42264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    i + 1 >= name.length() ||
42364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    !Character.isLetterOrDigit(name.charAt(i + 1))) break;
42464c64e7c25e6efe31fa53369ec49db442b68ff9amah            name = name.substring(0, i) + " dot " + name.substring(i + 1);
42564c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
42664c64e7c25e6efe31fa53369ec49db442b68ff9amah
42764c64e7c25e6efe31fa53369ec49db442b68ff9amah        // trim
42864c64e7c25e6efe31fa53369ec49db442b68ff9amah        name = name.trim();
42964c64e7c25e6efe31fa53369ec49db442b68ff9amah
43064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // ensure at least one alphanumeric character, or the pron engine will fail
43164c64e7c25e6efe31fa53369ec49db442b68ff9amah        for (int i = name.length() - 1; true; i--) {
43264c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (i < 0) return "";
43364c64e7c25e6efe31fa53369ec49db442b68ff9amah            char ch = name.charAt(i);
43464c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || ('0' <= ch && ch <= '9')) {
43564c64e7c25e6efe31fa53369ec49db442b68ff9amah                break;
43664c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
43764c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
43864c64e7c25e6efe31fa53369ec49db442b68ff9amah
43964c64e7c25e6efe31fa53369ec49db442b68ff9amah        return name;
44064c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
44164c64e7c25e6efe31fa53369ec49db442b68ff9amah
44264c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
44364c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Delete all g2g files in the directory indicated by {@link File},
44464c64e7c25e6efe31fa53369ec49db442b68ff9amah     * which is typically /data/data/com.android.voicedialer/files.
44564c64e7c25e6efe31fa53369ec49db442b68ff9amah     * There should only be one g2g file at any one time, with a hashcode
44664c64e7c25e6efe31fa53369ec49db442b68ff9amah     * embedded in it's name, but if stale ones are present, this will delete
44764c64e7c25e6efe31fa53369ec49db442b68ff9amah     * them all.
44864c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param context fetch directory for the stuffed and compiled g2g file.
44964c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
45064c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static void deleteAllG2GFiles(Context context) {
45164c64e7c25e6efe31fa53369ec49db442b68ff9amah        FileFilter ff = new FileFilter() {
45264c64e7c25e6efe31fa53369ec49db442b68ff9amah            public boolean accept(File f) {
45364c64e7c25e6efe31fa53369ec49db442b68ff9amah                String name = f.getName();
45464c64e7c25e6efe31fa53369ec49db442b68ff9amah                return name.endsWith(".g2g");
45564c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
45664c64e7c25e6efe31fa53369ec49db442b68ff9amah        };
45764c64e7c25e6efe31fa53369ec49db442b68ff9amah        File[] files = context.getFilesDir().listFiles(ff);
45864c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (files != null) {
45964c64e7c25e6efe31fa53369ec49db442b68ff9amah            for (File file : files) {
460d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato                if (false) Log.d(TAG, "deleteAllG2GFiles " + file);
46164c64e7c25e6efe31fa53369ec49db442b68ff9amah                file.delete();
46264c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
46364c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
46464c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
46564c64e7c25e6efe31fa53369ec49db442b68ff9amah
46664c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
46764c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Delete G2G and OpenEntries files, to force regeneration of the g2g file
46864c64e7c25e6efe31fa53369ec49db442b68ff9amah     * from scratch.
46964c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param context fetch directory for file.
47064c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
47164c64e7c25e6efe31fa53369ec49db442b68ff9amah    public static void deleteCachedGrammarFiles(Context context) {
47264c64e7c25e6efe31fa53369ec49db442b68ff9amah        deleteAllG2GFiles(context);
47364c64e7c25e6efe31fa53369ec49db442b68ff9amah        File oe = context.getFileStreamPath(OPEN_ENTRIES);
474d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato        if (false) Log.v(TAG, "deleteCachedGrammarFiles " + oe);
47564c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (oe.exists()) oe.delete();
47664c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
47764c64e7c25e6efe31fa53369ec49db442b68ff9amah
47864c64e7c25e6efe31fa53369ec49db442b68ff9amah    // NANP number formats
47964c64e7c25e6efe31fa53369ec49db442b68ff9amah    private final static String mNanpFormats =
48064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "xxx xxx xxxx\n" +
48164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "xxx xxxx\n" +
48264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "x11\n";
48364c64e7c25e6efe31fa53369ec49db442b68ff9amah
48464c64e7c25e6efe31fa53369ec49db442b68ff9amah    // a list of country codes
48564c64e7c25e6efe31fa53369ec49db442b68ff9amah    private final static String mPlusFormats =
48664c64e7c25e6efe31fa53369ec49db442b68ff9amah
48764c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
48864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 1: nanp (north american numbering plan), us, canada, caribbean
48964c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
49064c64e7c25e6efe31fa53369ec49db442b68ff9amah
49164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+1 xxx xxx xxxx\n" +         // nanp
49264c64e7c25e6efe31fa53369ec49db442b68ff9amah
49364c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
49464c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 2: africa, some atlantic and indian ocean islands
49564c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
49664c64e7c25e6efe31fa53369ec49db442b68ff9amah
49764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+20 x xxx xxxx\n" +          // Egypt
49864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+20 1x xxx xxxx\n" +         // Egypt
49964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+20 xx xxx xxxx\n" +         // Egypt
50064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+20 xxx xxx xxxx\n" +        // Egypt
50164c64e7c25e6efe31fa53369ec49db442b68ff9amah
50264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+212 xxxx xxxx\n" +          // Morocco
50364c64e7c25e6efe31fa53369ec49db442b68ff9amah
50464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+213 xx xx xx xx\n" +        // Algeria
50564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+213 xx xxx xxxx\n" +        // Algeria
50664c64e7c25e6efe31fa53369ec49db442b68ff9amah
50764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+216 xx xxx xxx\n" +         // Tunisia
50864c64e7c25e6efe31fa53369ec49db442b68ff9amah
50964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+218 xx xxx xxx\n" +         // Libya
51064c64e7c25e6efe31fa53369ec49db442b68ff9amah
51164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+22x \n" +
51264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+23x \n" +
51364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+24x \n" +
51464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+25x \n" +
51564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+26x \n" +
51664c64e7c25e6efe31fa53369ec49db442b68ff9amah
51764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+27 xx xxx xxxx\n" +         // South africa
51864c64e7c25e6efe31fa53369ec49db442b68ff9amah
51964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+290 x xxx\n" +              // Saint Helena, Tristan da Cunha
52064c64e7c25e6efe31fa53369ec49db442b68ff9amah
52164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+291 x xxx xxx\n" +          // Eritrea
52264c64e7c25e6efe31fa53369ec49db442b68ff9amah
52364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+297 xxx xxxx\n" +           // Aruba
52464c64e7c25e6efe31fa53369ec49db442b68ff9amah
52564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+298 xxx xxx\n" +            // Faroe Islands
52664c64e7c25e6efe31fa53369ec49db442b68ff9amah
52764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+299 xxx xxx\n" +            // Greenland
52864c64e7c25e6efe31fa53369ec49db442b68ff9amah
52964c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
53064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 3: europe, southern and small countries
53164c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
53264c64e7c25e6efe31fa53369ec49db442b68ff9amah
53364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+30 xxx xxx xxxx\n" +        // Greece
53464c64e7c25e6efe31fa53369ec49db442b68ff9amah
53564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+31 6 xxxx xxxx\n" +         // Netherlands
53664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+31 xx xxx xxxx\n" +         // Netherlands
53764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+31 xxx xx xxxx\n" +         // Netherlands
53864c64e7c25e6efe31fa53369ec49db442b68ff9amah
53964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+32 2 xxx xx xx\n" +         // Belgium
54064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+32 3 xxx xx xx\n" +         // Belgium
54164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+32 4xx xx xx xx\n" +        // Belgium
54264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+32 9 xxx xx xx\n" +         // Belgium
54364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+32 xx xx xx xx\n" +         // Belgium
54464c64e7c25e6efe31fa53369ec49db442b68ff9amah
54564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+33 xxx xxx xxx\n" +         // France
54664c64e7c25e6efe31fa53369ec49db442b68ff9amah
54764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+34 xxx xxx xxx\n" +        // Spain
54864c64e7c25e6efe31fa53369ec49db442b68ff9amah
54964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+351 3xx xxx xxx\n" +       // Portugal
55064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+351 7xx xxx xxx\n" +       // Portugal
55164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+351 8xx xxx xxx\n" +       // Portugal
55264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+351 xx xxx xxxx\n" +       // Portugal
55364c64e7c25e6efe31fa53369ec49db442b68ff9amah
55464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+352 xx xxxx\n" +           // Luxembourg
55564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+352 6x1 xxx xxx\n" +       // Luxembourg
55664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+352 \n" +                  // Luxembourg
55764c64e7c25e6efe31fa53369ec49db442b68ff9amah
55864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+353 xxx xxxx\n" +          // Ireland
55964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+353 xxxx xxxx\n" +         // Ireland
56064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+353 xx xxx xxxx\n" +       // Ireland
56164c64e7c25e6efe31fa53369ec49db442b68ff9amah
56264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+354 3xx xxx xxx\n" +       // Iceland
56364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+354 xxx xxxx\n" +          // Iceland
56464c64e7c25e6efe31fa53369ec49db442b68ff9amah
56564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+355 6x xxx xxxx\n" +       // Albania
56664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+355 xxx xxxx\n" +          // Albania
56764c64e7c25e6efe31fa53369ec49db442b68ff9amah
56864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+356 xx xx xx xx\n" +       // Malta
56964c64e7c25e6efe31fa53369ec49db442b68ff9amah
57064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+357 xx xx xx xx\n" +       // Cyprus
57164c64e7c25e6efe31fa53369ec49db442b68ff9amah
57264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+358 \n" +                  // Finland
57364c64e7c25e6efe31fa53369ec49db442b68ff9amah
57464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+359 \n" +                  // Bulgaria
57564c64e7c25e6efe31fa53369ec49db442b68ff9amah
57664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 1 xxx xxxx\n" +         // Hungary
57764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 20 xxx xxxx\n" +        // Hungary
57864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 21 xxx xxxx\n" +        // Hungary
57964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 30 xxx xxxx\n" +        // Hungary
58064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 70 xxx xxxx\n" +        // Hungary
58164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 71 xxx xxxx\n" +        // Hungary
58264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+36 xx xxx xxx\n" +         // Hungary
58364c64e7c25e6efe31fa53369ec49db442b68ff9amah
58464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+370 6x xxx xxx\n" +        // Lithuania
58564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+370 xxx xx xxx\n" +        // Lithuania
58664c64e7c25e6efe31fa53369ec49db442b68ff9amah
58764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+371 xxxx xxxx\n" +         // Latvia
58864c64e7c25e6efe31fa53369ec49db442b68ff9amah
58964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+372 5 xxx xxxx\n" +        // Estonia
59064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+372 xxx xxxx\n" +          // Estonia
59164c64e7c25e6efe31fa53369ec49db442b68ff9amah
59264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+373 6xx xx xxx\n" +        // Moldova
59364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+373 7xx xx xxx\n" +        // Moldova
59464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+373 xxx xxxxx\n" +         // Moldova
59564c64e7c25e6efe31fa53369ec49db442b68ff9amah
59664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+374 xx xxx xxx\n" +        // Armenia
59764c64e7c25e6efe31fa53369ec49db442b68ff9amah
59864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+375 xx xxx xxxx\n" +       // Belarus
59964c64e7c25e6efe31fa53369ec49db442b68ff9amah
60064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+376 xx xx xx\n" +          // Andorra
60164c64e7c25e6efe31fa53369ec49db442b68ff9amah
60264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+377 xxxx xxxx\n" +         // Monaco
60364c64e7c25e6efe31fa53369ec49db442b68ff9amah
60464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+378 xxx xxx xxxx\n" +      // San Marino
60564c64e7c25e6efe31fa53369ec49db442b68ff9amah
60664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+380 xxx xx xx xx\n" +      // Ukraine
60764c64e7c25e6efe31fa53369ec49db442b68ff9amah
60864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+381 xx xxx xxxx\n" +       // Serbia
60964c64e7c25e6efe31fa53369ec49db442b68ff9amah
61064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+382 xx xxx xxxx\n" +       // Montenegro
61164c64e7c25e6efe31fa53369ec49db442b68ff9amah
61264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+385 xx xxx xxxx\n" +       // Croatia
61364c64e7c25e6efe31fa53369ec49db442b68ff9amah
61464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+386 x xxx xxxx\n" +        // Slovenia
61564c64e7c25e6efe31fa53369ec49db442b68ff9amah
61664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+387 xx xx xx xx\n" +       // Bosnia and herzegovina
61764c64e7c25e6efe31fa53369ec49db442b68ff9amah
61864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+389 2 xxx xx xx\n" +       // Macedonia
61964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+389 xx xx xx xx\n" +       // Macedonia
62064c64e7c25e6efe31fa53369ec49db442b68ff9amah
62164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+39 xxx xxx xxx\n" +        // Italy
62264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+39 3xx xxx xxxx\n" +       // Italy
62364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+39 xx xxxx xxxx\n" +       // Italy
62464c64e7c25e6efe31fa53369ec49db442b68ff9amah
62564c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
62664c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 4: europe, northern countries
62764c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
62864c64e7c25e6efe31fa53369ec49db442b68ff9amah
62964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+40 xxx xxx xxx\n" +        // Romania
63064c64e7c25e6efe31fa53369ec49db442b68ff9amah
63164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+41 xx xxx xx xx\n" +       // Switzerland
63264c64e7c25e6efe31fa53369ec49db442b68ff9amah
63364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+420 xxx xxx xxx\n" +       // Czech republic
63464c64e7c25e6efe31fa53369ec49db442b68ff9amah
63564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+421 xxx xxx xxx\n" +       // Slovakia
63664c64e7c25e6efe31fa53369ec49db442b68ff9amah
63764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+421 xxx xxx xxxx\n" +      // Liechtenstein
63864c64e7c25e6efe31fa53369ec49db442b68ff9amah
63964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+43 \n" +                   // Austria
64064c64e7c25e6efe31fa53369ec49db442b68ff9amah
64164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+44 xxx xxx xxxx\n" +       // UK
64264c64e7c25e6efe31fa53369ec49db442b68ff9amah
64364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+45 xx xx xx xx\n" +        // Denmark
64464c64e7c25e6efe31fa53369ec49db442b68ff9amah
64564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+46 \n" +                   // Sweden
64664c64e7c25e6efe31fa53369ec49db442b68ff9amah
64764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+47 xxxx xxxx\n" +          // Norway
64864c64e7c25e6efe31fa53369ec49db442b68ff9amah
64964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+48 xx xxx xxxx\n" +        // Poland
65064c64e7c25e6efe31fa53369ec49db442b68ff9amah
65164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+49 1xx xxxx xxx\n" +       // Germany
65264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+49 1xx xxxx xxxx\n" +      // Germany
65364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+49 \n" +                   // Germany
65464c64e7c25e6efe31fa53369ec49db442b68ff9amah
65564c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
65664c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 5: latin america
65764c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
65864c64e7c25e6efe31fa53369ec49db442b68ff9amah
65964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+50x \n" +
66064c64e7c25e6efe31fa53369ec49db442b68ff9amah
66164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+51 9xx xxx xxx\n" +        // Peru
66264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+51 1 xxx xxxx\n" +         // Peru
66364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+51 xx xx xxxx\n" +         // Peru
66464c64e7c25e6efe31fa53369ec49db442b68ff9amah
66564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+52 1 xxx xxx xxxx\n" +     // Mexico
66664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+52 xxx xxx xxxx\n" +       // Mexico
66764c64e7c25e6efe31fa53369ec49db442b68ff9amah
66864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+53 xxxx xxxx\n" +          // Cuba
66964c64e7c25e6efe31fa53369ec49db442b68ff9amah
67064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+54 9 11 xxxx xxxx\n" +     // Argentina
67164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+54 9 xxx xxx xxxx\n" +     // Argentina
67264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+54 11 xxxx xxxx\n" +       // Argentina
67364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+54 xxx xxx xxxx\n" +       // Argentina
67464c64e7c25e6efe31fa53369ec49db442b68ff9amah
67564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+55 xx xxxx xxxx\n" +       // Brazil
67664c64e7c25e6efe31fa53369ec49db442b68ff9amah
67764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+56 2 xxxxxx\n" +           // Chile
67864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+56 9 xxxx xxxx\n" +        // Chile
67964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+56 xx xxxxxx\n" +          // Chile
68064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+56 xx xxxxxxx\n" +         // Chile
68164c64e7c25e6efe31fa53369ec49db442b68ff9amah
68264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+57 x xxx xxxx\n" +         // Columbia
68364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+57 3xx xxx xxxx\n" +       // Columbia
68464c64e7c25e6efe31fa53369ec49db442b68ff9amah
68564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+58 xxx xxx xxxx\n" +       // Venezuela
68664c64e7c25e6efe31fa53369ec49db442b68ff9amah
68764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+59x \n" +
68864c64e7c25e6efe31fa53369ec49db442b68ff9amah
68964c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
69064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 6: southeast asia and oceania
69164c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
69264c64e7c25e6efe31fa53369ec49db442b68ff9amah
69364c64e7c25e6efe31fa53369ec49db442b68ff9amah        // TODO is this right?
69464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 3 xxxx xxxx\n" +        // Malaysia
69564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 8x xxxxxx\n" +          // Malaysia
69664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 x xxx xxxx\n" +         // Malaysia
69764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 14 x xxx xxxx\n" +      // Malaysia
69864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 1x xxx xxxx\n" +        // Malaysia
69964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 x xxxx xxxx\n" +        // Malaysia
70064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+60 \n" +                   // Malaysia
70164c64e7c25e6efe31fa53369ec49db442b68ff9amah
70264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+61 4xx xxx xxx\n" +        // Australia
70364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+61 x xxxx xxxx\n" +        // Australia
70464c64e7c25e6efe31fa53369ec49db442b68ff9amah
70564c64e7c25e6efe31fa53369ec49db442b68ff9amah        // TODO: is this right?
70664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+62 8xx xxxx xxxx\n" +      // Indonesia
70764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+62 21 xxxxx\n" +           // Indonesia
70864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+62 xx xxxxxx\n" +          // Indonesia
70964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+62 xx xxx xxxx\n" +        // Indonesia
71064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+62 xx xxxx xxxx\n" +       // Indonesia
71164c64e7c25e6efe31fa53369ec49db442b68ff9amah
71264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+63 2 xxx xxxx\n" +         // Phillipines
71364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+63 xx xxx xxxx\n" +        // Phillipines
71464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+63 9xx xxx xxxx\n" +       // Phillipines
71564c64e7c25e6efe31fa53369ec49db442b68ff9amah
71664c64e7c25e6efe31fa53369ec49db442b68ff9amah        // TODO: is this right?
71764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+64 2 xxx xxxx\n" +         // New Zealand
71864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+64 2 xxx xxxx x\n" +       // New Zealand
71964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+64 2 xxx xxxx xx\n" +      // New Zealand
72064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+64 x xxx xxxx\n" +         // New Zealand
72164c64e7c25e6efe31fa53369ec49db442b68ff9amah
72264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+65 xxxx xxxx\n" +          // Singapore
72364c64e7c25e6efe31fa53369ec49db442b68ff9amah
72464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+66 8 xxxx xxxx\n" +        // Thailand
72564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+66 2 xxx xxxx\n" +         // Thailand
72664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+66 xx xx xxxx\n" +         // Thailand
72764c64e7c25e6efe31fa53369ec49db442b68ff9amah
72864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+67x \n" +
72964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+68x \n" +
73064c64e7c25e6efe31fa53369ec49db442b68ff9amah
73164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+690 x xxx\n" +             // Tokelau
73264c64e7c25e6efe31fa53369ec49db442b68ff9amah
73364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+691 xxx xxxx\n" +          // Micronesia
73464c64e7c25e6efe31fa53369ec49db442b68ff9amah
73564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+692 xxx xxxx\n" +          // marshall Islands
73664c64e7c25e6efe31fa53369ec49db442b68ff9amah
73764c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
73864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 7: russia and kazakstan
73964c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
74064c64e7c25e6efe31fa53369ec49db442b68ff9amah
74164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+7 6xx xx xxxxx\n" +        // Kazakstan
74264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+7 7xx 2 xxxxxx\n" +        // Kazakstan
74364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+7 7xx xx xxxxx\n" +        // Kazakstan
74464c64e7c25e6efe31fa53369ec49db442b68ff9amah
74564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+7 xxx xxx xx xx\n" +       // Russia
74664c64e7c25e6efe31fa53369ec49db442b68ff9amah
74764c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
74864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 8: east asia
74964c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
75064c64e7c25e6efe31fa53369ec49db442b68ff9amah
75164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+81 3 xxxx xxxx\n" +        // Japan
75264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+81 6 xxxx xxxx\n" +        // Japan
75364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+81 xx xxx xxxx\n" +        // Japan
75464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+81 x0 xxxx xxxx\n" +       // Japan
75564c64e7c25e6efe31fa53369ec49db442b68ff9amah
75664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+82 2 xxx xxxx\n" +         // South korea
75764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+82 2 xxxx xxxx\n" +        // South korea
75864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+82 xx xxxx xxxx\n" +       // South korea
75964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+82 xx xxx xxxx\n" +        // South korea
76064c64e7c25e6efe31fa53369ec49db442b68ff9amah
76164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+84 4 xxxx xxxx\n" +        // Vietnam
76264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+84 xx xxxx xxx\n" +        // Vietnam
76364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+84 xx xxxx xxxx\n" +       // Vietnam
76464c64e7c25e6efe31fa53369ec49db442b68ff9amah
76564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+850 \n" +                  // North Korea
76664c64e7c25e6efe31fa53369ec49db442b68ff9amah
76764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+852 xxxx xxxx\n" +         // Hong Kong
76864c64e7c25e6efe31fa53369ec49db442b68ff9amah
76964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+853 xxxx xxxx\n" +         // Macau
77064c64e7c25e6efe31fa53369ec49db442b68ff9amah
77164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+855 1x xxx xxx\n" +        // Cambodia
77264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+855 9x xxx xxx\n" +        // Cambodia
77364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+855 xx xx xx xx\n" +       // Cambodia
77464c64e7c25e6efe31fa53369ec49db442b68ff9amah
77564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+856 20 x xxx xxx\n" +      // Laos
77664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+856 xx xxx xxx\n" +        // Laos
77764c64e7c25e6efe31fa53369ec49db442b68ff9amah
77864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+852 xxxx xxxx\n" +         // Hong kong
77964c64e7c25e6efe31fa53369ec49db442b68ff9amah
78064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+86 10 xxxx xxxx\n" +       // China
78164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+86 2x xxxx xxxx\n" +       // China
78264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+86 xxx xxx xxxx\n" +       // China
78364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+86 xxx xxxx xxxx\n" +      // China
78464c64e7c25e6efe31fa53369ec49db442b68ff9amah
78564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+880 xx xxxx xxxx\n" +      // Bangladesh
78664c64e7c25e6efe31fa53369ec49db442b68ff9amah
78764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+886 \n" +                  // Taiwan
78864c64e7c25e6efe31fa53369ec49db442b68ff9amah
78964c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
79064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // zone 9: south asia, west asia, central asia, middle east
79164c64e7c25e6efe31fa53369ec49db442b68ff9amah        ////////////////////////////////////////////////////////////
79264c64e7c25e6efe31fa53369ec49db442b68ff9amah
79364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+90 xxx xxx xxxx\n" +       // Turkey
79464c64e7c25e6efe31fa53369ec49db442b68ff9amah
79564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+91 9x xx xxxxxx\n" +       // India
79664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+91 xx xxxx xxxx\n" +       // India
79764c64e7c25e6efe31fa53369ec49db442b68ff9amah
79864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+92 xx xxx xxxx\n" +        // Pakistan
79964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+92 3xx xxx xxxx\n" +       // Pakistan
80064c64e7c25e6efe31fa53369ec49db442b68ff9amah
80164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+93 70 xxx xxx\n" +         // Afghanistan
80264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+93 xx xxx xxxx\n" +        // Afghanistan
80364c64e7c25e6efe31fa53369ec49db442b68ff9amah
80464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+94 xx xxx xxxx\n" +        // Sri Lanka
80564c64e7c25e6efe31fa53369ec49db442b68ff9amah
80664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+95 1 xxx xxx\n" +          // Burma
80764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+95 2 xxx xxx\n" +          // Burma
80864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+95 xx xxxxx\n" +           // Burma
80964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+95 9 xxx xxxx\n" +         // Burma
81064c64e7c25e6efe31fa53369ec49db442b68ff9amah
81164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+960 xxx xxxx\n" +          // Maldives
81264c64e7c25e6efe31fa53369ec49db442b68ff9amah
81364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+961 x xxx xxx\n" +         // Lebanon
81464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+961 xx xxx xxx\n" +        // Lebanon
81564c64e7c25e6efe31fa53369ec49db442b68ff9amah
81664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+962 7 xxxx xxxx\n" +       // Jordan
81764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+962 x xxx xxxx\n" +        // Jordan
81864c64e7c25e6efe31fa53369ec49db442b68ff9amah
81964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+963 11 xxx xxxx\n" +       // Syria
82064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+963 xx xxx xxx\n" +        // Syria
82164c64e7c25e6efe31fa53369ec49db442b68ff9amah
82264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+964 \n" +                  // Iraq
82364c64e7c25e6efe31fa53369ec49db442b68ff9amah
82464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+965 xxxx xxxx\n" +         // Kuwait
82564c64e7c25e6efe31fa53369ec49db442b68ff9amah
82664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+966 5x xxx xxxx\n" +       // Saudi Arabia
82764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+966 x xxx xxxx\n" +        // Saudi Arabia
82864c64e7c25e6efe31fa53369ec49db442b68ff9amah
82964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+967 7xx xxx xxx\n" +       // Yemen
83064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+967 x xxx xxx\n" +         // Yemen
83164c64e7c25e6efe31fa53369ec49db442b68ff9amah
83264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+968 xxxx xxxx\n" +         // Oman
83364c64e7c25e6efe31fa53369ec49db442b68ff9amah
83464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+970 5x xxx xxxx\n" +       // Palestinian Authority
83564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+970 x xxx xxxx\n" +        // Palestinian Authority
83664c64e7c25e6efe31fa53369ec49db442b68ff9amah
83764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+971 5x xxx xxxx\n" +       // United Arab Emirates
83864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+971 x xxx xxxx\n" +        // United Arab Emirates
83964c64e7c25e6efe31fa53369ec49db442b68ff9amah
84064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+972 5x xxx xxxx\n" +       // Israel
84164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+972 x xxx xxxx\n" +        // Israel
84264c64e7c25e6efe31fa53369ec49db442b68ff9amah
84364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+973 xxxx xxxx\n" +         // Bahrain
84464c64e7c25e6efe31fa53369ec49db442b68ff9amah
84564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+974 xxx xxxx\n" +          // Qatar
84664c64e7c25e6efe31fa53369ec49db442b68ff9amah
84764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+975 1x xxx xxx\n" +        // Bhutan
84864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+975 x xxx xxx\n" +         // Bhutan
84964c64e7c25e6efe31fa53369ec49db442b68ff9amah
85064c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+976 \n" +                  // Mongolia
85164c64e7c25e6efe31fa53369ec49db442b68ff9amah
85264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+977 xxxx xxxx\n" +         // Nepal
85364c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+977 98 xxxx xxxx\n" +      // Nepal
85464c64e7c25e6efe31fa53369ec49db442b68ff9amah
85564c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+98 xxx xxx xxxx\n" +       // Iran
85664c64e7c25e6efe31fa53369ec49db442b68ff9amah
85764c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+992 xxx xxx xxx\n" +       // Tajikistan
85864c64e7c25e6efe31fa53369ec49db442b68ff9amah
85964c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+993 xxxx xxxx\n" +         // Turkmenistan
86064c64e7c25e6efe31fa53369ec49db442b68ff9amah
86164c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+994 xx xxx xxxx\n" +       // Azerbaijan
86264c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+994 xxx xxxxx\n" +         // Azerbaijan
86364c64e7c25e6efe31fa53369ec49db442b68ff9amah
86464c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+995 xx xxx xxx\n" +        // Georgia
86564c64e7c25e6efe31fa53369ec49db442b68ff9amah
86664c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+996 xxx xxx xxx\n" +       // Kyrgyzstan
86764c64e7c25e6efe31fa53369ec49db442b68ff9amah
86864c64e7c25e6efe31fa53369ec49db442b68ff9amah        "+998 xx xxx xxxx\n";        // Uzbekistan
86964c64e7c25e6efe31fa53369ec49db442b68ff9amah
87064c64e7c25e6efe31fa53369ec49db442b68ff9amah
87164c64e7c25e6efe31fa53369ec49db442b68ff9amah    // TODO: need to handle variable number notation
87264c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static String formatNumber(String formats, String number) {
87364c64e7c25e6efe31fa53369ec49db442b68ff9amah        number = number.trim();
87464c64e7c25e6efe31fa53369ec49db442b68ff9amah        final int nlen = number.length();
87564c64e7c25e6efe31fa53369ec49db442b68ff9amah        final int formatslen = formats.length();
87664c64e7c25e6efe31fa53369ec49db442b68ff9amah        StringBuffer sb = new StringBuffer();
87764c64e7c25e6efe31fa53369ec49db442b68ff9amah
87864c64e7c25e6efe31fa53369ec49db442b68ff9amah        // loop over country codes
87964c64e7c25e6efe31fa53369ec49db442b68ff9amah        for (int f = 0; f < formatslen; ) {
88064c64e7c25e6efe31fa53369ec49db442b68ff9amah            sb.setLength(0);
88164c64e7c25e6efe31fa53369ec49db442b68ff9amah            int n = 0;
88264c64e7c25e6efe31fa53369ec49db442b68ff9amah
88364c64e7c25e6efe31fa53369ec49db442b68ff9amah            // loop over letters of pattern
88464c64e7c25e6efe31fa53369ec49db442b68ff9amah            while (true) {
88564c64e7c25e6efe31fa53369ec49db442b68ff9amah                final char fch = formats.charAt(f);
88664c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (fch == '\n' && n >= nlen) return sb.toString();
88764c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (fch == '\n' || n >= nlen) break;
88864c64e7c25e6efe31fa53369ec49db442b68ff9amah                final char nch = number.charAt(n);
88964c64e7c25e6efe31fa53369ec49db442b68ff9amah                // pattern matches number
89064c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (fch == nch || (fch == 'x' && Character.isDigit(nch))) {
89164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    f++;
89264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    n++;
89364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    sb.append(nch);
89464c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
89564c64e7c25e6efe31fa53369ec49db442b68ff9amah                // don't match ' ' in pattern, but insert into result
89664c64e7c25e6efe31fa53369ec49db442b68ff9amah                else if (fch == ' ') {
89764c64e7c25e6efe31fa53369ec49db442b68ff9amah                    f++;
89864c64e7c25e6efe31fa53369ec49db442b68ff9amah                    sb.append(' ');
89964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    // ' ' at end -> match all the rest
90064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    if (formats.charAt(f) == '\n') {
90164c64e7c25e6efe31fa53369ec49db442b68ff9amah                        return sb.append(number, n, nlen).toString();
90264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
90364c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
90464c64e7c25e6efe31fa53369ec49db442b68ff9amah                // match failed
90564c64e7c25e6efe31fa53369ec49db442b68ff9amah                else break;
90664c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
90764c64e7c25e6efe31fa53369ec49db442b68ff9amah
90864c64e7c25e6efe31fa53369ec49db442b68ff9amah            // step to the next pattern
90964c64e7c25e6efe31fa53369ec49db442b68ff9amah            f = formats.indexOf('\n', f) + 1;
91064c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (f == 0) break;
91164c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
91264c64e7c25e6efe31fa53369ec49db442b68ff9amah
91364c64e7c25e6efe31fa53369ec49db442b68ff9amah        return null;
91464c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
91564c64e7c25e6efe31fa53369ec49db442b68ff9amah
91664c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
91764c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Format a phone number string.
91864c64e7c25e6efe31fa53369ec49db442b68ff9amah     * At some point, PhoneNumberUtils.formatNumber will handle this.
91964c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param num phone number string.
92064c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @return formatted phone number string.
92164c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
92264c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static String formatNumber(String num) {
92364c64e7c25e6efe31fa53369ec49db442b68ff9amah        String fmt = null;
92464c64e7c25e6efe31fa53369ec49db442b68ff9amah
92564c64e7c25e6efe31fa53369ec49db442b68ff9amah        fmt = formatNumber(mPlusFormats, num);
92664c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (fmt != null) return fmt;
92764c64e7c25e6efe31fa53369ec49db442b68ff9amah
92864c64e7c25e6efe31fa53369ec49db442b68ff9amah        fmt = formatNumber(mNanpFormats, num);
92964c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (fmt != null) return fmt;
93064c64e7c25e6efe31fa53369ec49db442b68ff9amah
93164c64e7c25e6efe31fa53369ec49db442b68ff9amah        return null;
93264c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
93364c64e7c25e6efe31fa53369ec49db442b68ff9amah
93464c64e7c25e6efe31fa53369ec49db442b68ff9amah    /**
93564c64e7c25e6efe31fa53369ec49db442b68ff9amah     * Called when recognition succeeds.  It receives a list
93664c64e7c25e6efe31fa53369ec49db442b68ff9amah     * of results, builds a corresponding list of Intents, and
93764c64e7c25e6efe31fa53369ec49db442b68ff9amah     * passes them to the {@link RecognizerClient}, which selects and
93864c64e7c25e6efe31fa53369ec49db442b68ff9amah     * performs a corresponding action.
93964c64e7c25e6efe31fa53369ec49db442b68ff9amah     * @param recognizerClient the client that will be sent the results
94064c64e7c25e6efe31fa53369ec49db442b68ff9amah     */
94164c64e7c25e6efe31fa53369ec49db442b68ff9amah    protected  void onRecognitionSuccess(RecognizerClient recognizerClient)
94264c64e7c25e6efe31fa53369ec49db442b68ff9amah            throws InterruptedException {
943d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato        if (false) Log.d(TAG, "onRecognitionSuccess");
94464c64e7c25e6efe31fa53369ec49db442b68ff9amah
94564c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (mLogger != null) mLogger.logNbestHeader();
94664c64e7c25e6efe31fa53369ec49db442b68ff9amah
94764c64e7c25e6efe31fa53369ec49db442b68ff9amah        ArrayList<Intent> intents = new ArrayList<Intent>();
94864c64e7c25e6efe31fa53369ec49db442b68ff9amah
9497a55150b308ed03d41091e4c3ac693d6eb0ab145mah        int highestConfidence = 0;
9507a55150b308ed03d41091e4c3ac693d6eb0ab145mah        int examineLimit = RESULT_LIMIT;
9517a55150b308ed03d41091e4c3ac693d6eb0ab145mah        if (mMinimizeResults) {
9527a55150b308ed03d41091e4c3ac693d6eb0ab145mah            examineLimit = 1;
9537a55150b308ed03d41091e4c3ac693d6eb0ab145mah        }
95464c64e7c25e6efe31fa53369ec49db442b68ff9amah        for (int result = 0; result < mSrec.getResultCount() &&
9557a55150b308ed03d41091e4c3ac693d6eb0ab145mah                intents.size() < examineLimit; result++) {
95664c64e7c25e6efe31fa53369ec49db442b68ff9amah
95764c64e7c25e6efe31fa53369ec49db442b68ff9amah            // parse the semanticMeaning string and build an Intent
95864c64e7c25e6efe31fa53369ec49db442b68ff9amah            String conf = mSrec.getResult(result, Recognizer.KEY_CONFIDENCE);
95964c64e7c25e6efe31fa53369ec49db442b68ff9amah            String literal = mSrec.getResult(result, Recognizer.KEY_LITERAL);
96064c64e7c25e6efe31fa53369ec49db442b68ff9amah            String semantic = mSrec.getResult(result, Recognizer.KEY_MEANING);
96164c64e7c25e6efe31fa53369ec49db442b68ff9amah            String msg = "conf=" + conf + " lit=" + literal + " sem=" + semantic;
962d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato            if (false) Log.d(TAG, msg);
9637a55150b308ed03d41091e4c3ac693d6eb0ab145mah            int confInt = Integer.parseInt(conf);
9647a55150b308ed03d41091e4c3ac693d6eb0ab145mah            if (highestConfidence < confInt) highestConfidence = confInt;
9657a55150b308ed03d41091e4c3ac693d6eb0ab145mah            if (confInt < MINIMUM_CONFIDENCE || confInt * 2 < highestConfidence) {
966d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato                if (false) Log.d(TAG, "confidence too low, dropping");
9677a55150b308ed03d41091e4c3ac693d6eb0ab145mah                break;
9687a55150b308ed03d41091e4c3ac693d6eb0ab145mah            }
96964c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (mLogger != null) mLogger.logLine(msg);
97064c64e7c25e6efe31fa53369ec49db442b68ff9amah            String[] commands = semantic.trim().split(" ");
97164c64e7c25e6efe31fa53369ec49db442b68ff9amah
97264c64e7c25e6efe31fa53369ec49db442b68ff9amah            // DIAL 650 867 5309
97364c64e7c25e6efe31fa53369ec49db442b68ff9amah            // DIAL 867 5309
97464c64e7c25e6efe31fa53369ec49db442b68ff9amah            // DIAL 911
9757a55150b308ed03d41091e4c3ac693d6eb0ab145mah            if ("DIAL".equalsIgnoreCase(commands[0])) {
97664c64e7c25e6efe31fa53369ec49db442b68ff9amah                Uri uri = Uri.fromParts("tel", commands[1], null);
97764c64e7c25e6efe31fa53369ec49db442b68ff9amah                String num =  formatNumber(commands[1]);
97864c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (num != null) {
97964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    addCallIntent(intents, uri,
9807a55150b308ed03d41091e4c3ac693d6eb0ab145mah                            literal.split(" ")[0].trim() + " " + num, "", 0);
98164c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
98264c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
98364c64e7c25e6efe31fa53369ec49db442b68ff9amah
98464c64e7c25e6efe31fa53369ec49db442b68ff9amah            // CALL JACK JONES
98585a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa            // commands should become ["CALL", id, id, ..] reflecting addNameEntriesToGrammar().
98685a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa            else if ("CALL".equalsIgnoreCase(commands[0])
98785a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    && commands.length >= PHONE_ID_COUNT + 1) {
98864c64e7c25e6efe31fa53369ec49db442b68ff9amah                // parse the ids
98964c64e7c25e6efe31fa53369ec49db442b68ff9amah                long contactId = Long.parseLong(commands[1]); // people table
99085a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                long primaryId   = Long.parseLong(commands[2]); // phones table
99164c64e7c25e6efe31fa53369ec49db442b68ff9amah                long homeId    = Long.parseLong(commands[3]); // phones table
99264c64e7c25e6efe31fa53369ec49db442b68ff9amah                long mobileId  = Long.parseLong(commands[4]); // phones table
99364c64e7c25e6efe31fa53369ec49db442b68ff9amah                long workId    = Long.parseLong(commands[5]); // phones table
99464c64e7c25e6efe31fa53369ec49db442b68ff9amah                long otherId   = Long.parseLong(commands[6]); // phones table
99585a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                long fallbackId = Long.parseLong(commands[7]); // phones table
99664c64e7c25e6efe31fa53369ec49db442b68ff9amah                Resources res  = mActivity.getResources();
99764c64e7c25e6efe31fa53369ec49db442b68ff9amah
99864c64e7c25e6efe31fa53369ec49db442b68ff9amah                int count = 0;
99964c64e7c25e6efe31fa53369ec49db442b68ff9amah
100064c64e7c25e6efe31fa53369ec49db442b68ff9amah                //
100164c64e7c25e6efe31fa53369ec49db442b68ff9amah                // generate the best entry corresponding to what was said
100264c64e7c25e6efe31fa53369ec49db442b68ff9amah                //
100364c64e7c25e6efe31fa53369ec49db442b68ff9amah
100464c64e7c25e6efe31fa53369ec49db442b68ff9amah                // 'CALL JACK JONES AT HOME|MOBILE|WORK|OTHER'
100585a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                if (commands.length == PHONE_ID_COUNT + 2) {
100685a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    // The last command should imply the type of the phone number.
100785a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    final String spokenPhoneIdCommand = commands[PHONE_ID_COUNT + 1];
100864c64e7c25e6efe31fa53369ec49db442b68ff9amah                    long spokenPhoneId =
100985a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                            "H".equalsIgnoreCase(spokenPhoneIdCommand) ? homeId :
101085a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                            "M".equalsIgnoreCase(spokenPhoneIdCommand) ? mobileId :
101185a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                            "W".equalsIgnoreCase(spokenPhoneIdCommand) ? workId :
101285a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                            "O".equalsIgnoreCase(spokenPhoneIdCommand) ? otherId :
101364c64e7c25e6efe31fa53369ec49db442b68ff9amah                             VoiceContact.ID_UNDEFINED;
101464c64e7c25e6efe31fa53369ec49db442b68ff9amah                    if (spokenPhoneId != VoiceContact.ID_UNDEFINED) {
101564c64e7c25e6efe31fa53369ec49db442b68ff9amah                        addCallIntent(intents, ContentUris.withAppendedId(
101664c64e7c25e6efe31fa53369ec49db442b68ff9amah                                Phone.CONTENT_URI, spokenPhoneId),
101785a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                                literal, spokenPhoneIdCommand, 0);
101864c64e7c25e6efe31fa53369ec49db442b68ff9amah                        count++;
101964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
102064c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
102164c64e7c25e6efe31fa53369ec49db442b68ff9amah
102264c64e7c25e6efe31fa53369ec49db442b68ff9amah                // 'CALL JACK JONES', with valid default phoneId
102385a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                else if (commands.length == PHONE_ID_COUNT + 1) {
10247a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    String phoneType = null;
10257a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    CharSequence phoneIdMsg = null;
102685a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    if (primaryId == VoiceContact.ID_UNDEFINED) {
10277a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneType = null;
10287a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneIdMsg = null;
102985a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    } else if (primaryId == homeId) {
10307a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneType = "H";
10317a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneIdMsg = res.getText(R.string.at_home);
103285a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    } else if (primaryId == mobileId) {
10337a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneType = "M";
10347a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneIdMsg = res.getText(R.string.on_mobile);
103585a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    } else if (primaryId == workId) {
10367a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneType = "W";
10377a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneIdMsg = res.getText(R.string.at_work);
103885a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    } else if (primaryId == otherId) {
10397a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneType = "O";
10407a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        phoneIdMsg = res.getText(R.string.at_other);
10417a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    }
104264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    if (phoneIdMsg != null) {
104364c64e7c25e6efe31fa53369ec49db442b68ff9amah                        addCallIntent(intents, ContentUris.withAppendedId(
104485a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                                Phone.CONTENT_URI, primaryId),
10457a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                literal + phoneIdMsg, phoneType, 0);
104664c64e7c25e6efe31fa53369ec49db442b68ff9amah                        count++;
104764c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
104864c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
104964c64e7c25e6efe31fa53369ec49db442b68ff9amah
10507a55150b308ed03d41091e4c3ac693d6eb0ab145mah                if (count == 0 || !mMinimizeResults) {
10517a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    //
10527a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    // generate all other entries for this person
10537a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    //
10547a55150b308ed03d41091e4c3ac693d6eb0ab145mah
10557a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    // trim last two words, ie 'at home', etc
10567a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    String lit = literal;
105785a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    if (commands.length == PHONE_ID_COUNT + 2) {
10587a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        String[] words = literal.trim().split(" ");
10597a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        StringBuffer sb = new StringBuffer();
10607a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        for (int i = 0; i < words.length - 2; i++) {
10617a55150b308ed03d41091e4c3ac693d6eb0ab145mah                            if (i != 0) {
10627a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                sb.append(' ');
10637a55150b308ed03d41091e4c3ac693d6eb0ab145mah                            }
10647a55150b308ed03d41091e4c3ac693d6eb0ab145mah                            sb.append(words[i]);
106564c64e7c25e6efe31fa53369ec49db442b68ff9amah                        }
10667a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        lit = sb.toString();
106764c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
106864c64e7c25e6efe31fa53369ec49db442b68ff9amah
10697a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    //  add 'CALL JACK JONES at home' using phoneId
10707a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    if (homeId != VoiceContact.ID_UNDEFINED) {
10717a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        addCallIntent(intents, ContentUris.withAppendedId(
10727a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                Phone.CONTENT_URI, homeId),
10737a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                lit + res.getText(R.string.at_home), "H",  0);
10747a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        count++;
10757a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    }
107664c64e7c25e6efe31fa53369ec49db442b68ff9amah
10777a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    //  add 'CALL JACK JONES on mobile' using mobileId
10787a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    if (mobileId != VoiceContact.ID_UNDEFINED) {
10797a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        addCallIntent(intents, ContentUris.withAppendedId(
10807a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                Phone.CONTENT_URI, mobileId),
10817a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                lit + res.getText(R.string.on_mobile), "M", 0);
10827a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        count++;
10837a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    }
108464c64e7c25e6efe31fa53369ec49db442b68ff9amah
10857a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    //  add 'CALL JACK JONES at work' using workId
10867a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    if (workId != VoiceContact.ID_UNDEFINED) {
10877a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        addCallIntent(intents, ContentUris.withAppendedId(
10887a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                Phone.CONTENT_URI, workId),
10897a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                lit + res.getText(R.string.at_work), "W", 0);
10907a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        count++;
10917a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    }
109264c64e7c25e6efe31fa53369ec49db442b68ff9amah
10937a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    //  add 'CALL JACK JONES at other' using otherId
10947a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    if (otherId != VoiceContact.ID_UNDEFINED) {
10957a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        addCallIntent(intents, ContentUris.withAppendedId(
10967a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                Phone.CONTENT_URI, otherId),
10977a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                lit + res.getText(R.string.at_other), "O", 0);
10987a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        count++;
10997a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    }
110064c64e7c25e6efe31fa53369ec49db442b68ff9amah
110185a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    if (fallbackId != VoiceContact.ID_UNDEFINED) {
110285a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                        addCallIntent(intents, ContentUris.withAppendedId(
110385a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                                Phone.CONTENT_URI, fallbackId),
110485a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                                lit, "", 0);
110585a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                        count++;
110685a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                    }
110764c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
110864c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
11098c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon
11108c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon            else if ("X".equalsIgnoreCase(commands[0])) {
11118c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon                Intent intent = new Intent(RecognizerEngine.ACTION_RECOGNIZER_RESULT, null);
11128c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon                intent.putExtra(RecognizerEngine.SENTENCE_EXTRA, literal);
11138c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon                intent.putExtra(RecognizerEngine.SEMANTIC_EXTRA, semantic);
11148c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon                addIntent(intents, intent);
11158c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon            }
11168c7aac011e578450a6837ed4ba55b1167c17bf46Martin Hibdon
111764c64e7c25e6efe31fa53369ec49db442b68ff9amah            // "CALL VoiceMail"
11187a55150b308ed03d41091e4c3ac693d6eb0ab145mah            else if ("voicemail".equalsIgnoreCase(commands[0]) && commands.length == 1) {
111964c64e7c25e6efe31fa53369ec49db442b68ff9amah                addCallIntent(intents, Uri.fromParts("voicemail", "x", null),
11207a55150b308ed03d41091e4c3ac693d6eb0ab145mah                        literal, "", Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
112164c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
112264c64e7c25e6efe31fa53369ec49db442b68ff9amah
112364c64e7c25e6efe31fa53369ec49db442b68ff9amah            // "REDIAL"
11247a55150b308ed03d41091e4c3ac693d6eb0ab145mah            else if ("redial".equalsIgnoreCase(commands[0]) && commands.length == 1) {
112564c64e7c25e6efe31fa53369ec49db442b68ff9amah                String number = VoiceContact.redialNumber(mActivity);
112664c64e7c25e6efe31fa53369ec49db442b68ff9amah                if (number != null) {
11277a55150b308ed03d41091e4c3ac693d6eb0ab145mah                    addCallIntent(intents, Uri.fromParts("tel", number, null),
11287a55150b308ed03d41091e4c3ac693d6eb0ab145mah                            literal, "", Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
112964c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
113064c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
113164c64e7c25e6efe31fa53369ec49db442b68ff9amah
113264c64e7c25e6efe31fa53369ec49db442b68ff9amah            // "Intent ..."
113364c64e7c25e6efe31fa53369ec49db442b68ff9amah            else if ("Intent".equalsIgnoreCase(commands[0])) {
113464c64e7c25e6efe31fa53369ec49db442b68ff9amah                for (int i = 1; i < commands.length; i++) {
113564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    try {
113664c64e7c25e6efe31fa53369ec49db442b68ff9amah                        Intent intent = Intent.getIntent(commands[i]);
113764c64e7c25e6efe31fa53369ec49db442b68ff9amah                        if (intent.getStringExtra(SENTENCE_EXTRA) == null) {
113864c64e7c25e6efe31fa53369ec49db442b68ff9amah                            intent.putExtra(SENTENCE_EXTRA, literal);
113964c64e7c25e6efe31fa53369ec49db442b68ff9amah                        }
114064c64e7c25e6efe31fa53369ec49db442b68ff9amah                        addIntent(intents, intent);
114164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    } catch (URISyntaxException e) {
1142d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato                        if (false) {
11437a55150b308ed03d41091e4c3ac693d6eb0ab145mah                            Log.d(TAG, "onRecognitionSuccess: poorly " +
11447a55150b308ed03d41091e4c3ac693d6eb0ab145mah                                    "formed URI in grammar" + e);
114564c64e7c25e6efe31fa53369ec49db442b68ff9amah                        }
114664c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
114764c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
114864c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
114964c64e7c25e6efe31fa53369ec49db442b68ff9amah
115064c64e7c25e6efe31fa53369ec49db442b68ff9amah            // "OPEN ..."
11515f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            else if ("OPEN".equalsIgnoreCase(commands[0]) && mAllowOpenEntries) {
115264c64e7c25e6efe31fa53369ec49db442b68ff9amah                PackageManager pm = mActivity.getPackageManager();
11534a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (commands.length > 1 & mOpenEntries != null) {
1154e5258ff473c778362d612389db79b740e9c35911Martin Hibdon                    // the semantic value is equal to the literal in this case.
11554a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    // We have to do the mapping from this text to the
11564a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    // componentname ourselves.  See Bug: 2457238.
11574a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    // The problem is that the list of all componentnames
11584a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    // can be pretty large and overflow the limit that
11594a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    // the recognizer has.
11604a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    String meaning = mOpenEntries.get(commands[1]);
11614a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    String[] components = meaning.trim().split(" ");
11624a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    for (int i=0; i < components.length; i++) {
11634a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        String component = components[i];
11644a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        Intent intent = new Intent(Intent.ACTION_MAIN);
116564c64e7c25e6efe31fa53369ec49db442b68ff9amah                        intent.addCategory("android.intent.category.VOICE_LAUNCH");
11664a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        String packageName = component.substring(
11674a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                                0, component.lastIndexOf('/'));
11684a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        String className = component.substring(
11694a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                                component.lastIndexOf('/')+1, component.length());
117027d520022f552e3e4b17b00d6ec4db9306fe7deaMartin Hibdon                        intent.setClassName(packageName, className);
11714a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        List<ResolveInfo> riList = pm.queryIntentActivities(intent, 0);
11724a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        for (ResolveInfo ri : riList) {
11734a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                            String label = ri.loadLabel(pm).toString();
11744a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                            intent = new Intent(Intent.ACTION_MAIN);
11754a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                            intent.addCategory("android.intent.category.VOICE_LAUNCH");
11764a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                            intent.setClassName(packageName, className);
11774a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                            intent.putExtra(SENTENCE_EXTRA, literal.split(" ")[0] + " " + label);
11784a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                            addIntent(intents, intent);
11794a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                        }
118064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
118164c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
118264c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
118364c64e7c25e6efe31fa53369ec49db442b68ff9amah
118464c64e7c25e6efe31fa53369ec49db442b68ff9amah            // can't parse result
118564c64e7c25e6efe31fa53369ec49db442b68ff9amah            else {
1186d3694c0511a27f1fb44fa2760ee0d4562ffe1066Joe Onorato                if (false) Log.d(TAG, "onRecognitionSuccess: parse error");
118764c64e7c25e6efe31fa53369ec49db442b68ff9amah            }
118864c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
118964c64e7c25e6efe31fa53369ec49db442b68ff9amah
119064c64e7c25e6efe31fa53369ec49db442b68ff9amah        // log if requested
119164c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (mLogger != null) mLogger.logIntents(intents);
119264c64e7c25e6efe31fa53369ec49db442b68ff9amah
119364c64e7c25e6efe31fa53369ec49db442b68ff9amah        // bail out if cancelled
119464c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (Thread.interrupted()) throw new InterruptedException();
119564c64e7c25e6efe31fa53369ec49db442b68ff9amah
119664c64e7c25e6efe31fa53369ec49db442b68ff9amah        if (intents.size() == 0) {
119764c64e7c25e6efe31fa53369ec49db442b68ff9amah            // TODO: strip HOME|MOBILE|WORK and try default here?
119864c64e7c25e6efe31fa53369ec49db442b68ff9amah            recognizerClient.onRecognitionFailure("No Intents generated");
119964c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
120064c64e7c25e6efe31fa53369ec49db442b68ff9amah        else {
120164c64e7c25e6efe31fa53369ec49db442b68ff9amah            recognizerClient.onRecognitionSuccess(
120264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    intents.toArray(new Intent[intents.size()]));
120364c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
120464c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
120564c64e7c25e6efe31fa53369ec49db442b68ff9amah
120664c64e7c25e6efe31fa53369ec49db442b68ff9amah    // only add if different
120764c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static void addCallIntent(ArrayList<Intent> intents, Uri uri, String literal,
12087a55150b308ed03d41091e4c3ac693d6eb0ab145mah            String phoneType, int flags) {
120985a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa        Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri)
121085a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                .setFlags(flags)
121185a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                .putExtra(SENTENCE_EXTRA, literal)
121285a421c6d6bf1fdbbee134d99c1a7450b00ce8fcDaisuke Miyakawa                .putExtra(PHONE_TYPE_EXTRA, phoneType);
121364c64e7c25e6efe31fa53369ec49db442b68ff9amah        addIntent(intents, intent);
121464c64e7c25e6efe31fa53369ec49db442b68ff9amah    }
121564c64e7c25e6efe31fa53369ec49db442b68ff9amah}
1216