diff options
author | Daisuke Miyakawa <dmiyakawa@google.com> | 2011-11-28 14:07:11 -0800 |
---|---|---|
committer | Daisuke Miyakawa <dmiyakawa@google.com> | 2011-12-02 15:58:30 -0800 |
commit | 85a421c6d6bf1fdbbee134d99c1a7450b00ce8fc (patch) | |
tree | 6aba74d716bed217928b1ad58b20a2f8090a48d6 | |
parent | 97d226af8140ae81e37c027e489a14cbe61bdf30 (diff) | |
download | VoiceDialer-85a421c6d6bf1fdbbee134d99c1a7450b00ce8fc.tar.gz |
Recognize phone numbers without supported types
Currently VoiceDialer cannot show a candidate when it has a type
the recognition engine cannot recognize. For example if a
contact has one phone number with the type CUSTOM, VoiceDialer
never shows the person as a candidate even when a user ask so
("Call XXX").
This change prepares "fallback" phone number id and use it when
there's no other available ids with recognizable types, to support
the case above.
TESTED:
- Have a contact (say "Ada" here) with several phone numbers one
of which must have a custom type which isn't supported by
VoiceDialer ("CUSTOM"). Say "Call Ada" and see if that custom
phone number appears as another entry ("Call Ada")
- Try "Call Ada at home" or other voice command and see they work
as before.
Bug: 5585945
Change-Id: Idd0e539209cd14e786007e8ce0b121c165994c5a
-rw-r--r-- | src/com/android/voicedialer/CommandRecognizerEngine.java | 82 | ||||
-rw-r--r-- | src/com/android/voicedialer/VoiceContact.java | 32 |
2 files changed, 67 insertions, 47 deletions
diff --git a/src/com/android/voicedialer/CommandRecognizerEngine.java b/src/com/android/voicedialer/CommandRecognizerEngine.java index 25f0019..91b37e1 100644 --- a/src/com/android/voicedialer/CommandRecognizerEngine.java +++ b/src/com/android/voicedialer/CommandRecognizerEngine.java @@ -24,9 +24,9 @@ import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.net.Uri; import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Contacts; import android.speech.srec.Recognizer; import android.util.Log; + import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; @@ -181,6 +181,11 @@ public class CommandRecognizerEngine extends RecognizerEngine { } /** + * Number of phone ids appended to a grammer in {@link #addNameEntriesToGrammar(List)}. + */ + private static final int PHONE_ID_COUNT = 7; + + /** * Add a list of names to the grammar * @param contacts list of VoiceContacts to be added. */ @@ -189,20 +194,22 @@ public class CommandRecognizerEngine extends RecognizerEngine { if (false) Log.d(TAG, "addNameEntriesToGrammar " + contacts.size()); HashSet<String> entries = new HashSet<String>(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); int count = 0; for (VoiceContact contact : contacts) { if (Thread.interrupted()) throw new InterruptedException(); String name = scrubName(contact.mName); if (name.length() == 0 || !entries.add(name)) continue; sb.setLength(0); + // The number of ids appended here must be same as PHONE_ID_COUNT. sb.append("V='"); sb.append(contact.mContactId).append(' '); sb.append(contact.mPrimaryId).append(' '); sb.append(contact.mHomeId).append(' '); sb.append(contact.mMobileId).append(' '); sb.append(contact.mWorkId).append(' '); - sb.append(contact.mOtherId); + sb.append(contact.mOtherId).append(' '); + sb.append(contact.mFallbackId); sb.append("'"); try { mSrecGrammar.addWordToSlot("@Names", name, null, 1, sb.toString()); @@ -975,14 +982,17 @@ public class CommandRecognizerEngine extends RecognizerEngine { } // CALL JACK JONES - else if ("CALL".equalsIgnoreCase(commands[0]) && commands.length >= 7) { + // commands should become ["CALL", id, id, ..] reflecting addNameEntriesToGrammar(). + else if ("CALL".equalsIgnoreCase(commands[0]) + && commands.length >= PHONE_ID_COUNT + 1) { // parse the ids long contactId = Long.parseLong(commands[1]); // people table - long phoneId = Long.parseLong(commands[2]); // phones table + long primaryId = Long.parseLong(commands[2]); // phones table long homeId = Long.parseLong(commands[3]); // phones table long mobileId = Long.parseLong(commands[4]); // phones table long workId = Long.parseLong(commands[5]); // phones table long otherId = Long.parseLong(commands[6]); // phones table + long fallbackId = Long.parseLong(commands[7]); // phones table Resources res = mActivity.getResources(); int count = 0; @@ -992,44 +1002,46 @@ public class CommandRecognizerEngine extends RecognizerEngine { // // 'CALL JACK JONES AT HOME|MOBILE|WORK|OTHER' - if (commands.length == 8) { + if (commands.length == PHONE_ID_COUNT + 2) { + // The last command should imply the type of the phone number. + final String spokenPhoneIdCommand = commands[PHONE_ID_COUNT + 1]; long spokenPhoneId = - "H".equalsIgnoreCase(commands[7]) ? homeId : - "M".equalsIgnoreCase(commands[7]) ? mobileId : - "W".equalsIgnoreCase(commands[7]) ? workId : - "O".equalsIgnoreCase(commands[7]) ? otherId : + "H".equalsIgnoreCase(spokenPhoneIdCommand) ? homeId : + "M".equalsIgnoreCase(spokenPhoneIdCommand) ? mobileId : + "W".equalsIgnoreCase(spokenPhoneIdCommand) ? workId : + "O".equalsIgnoreCase(spokenPhoneIdCommand) ? otherId : VoiceContact.ID_UNDEFINED; if (spokenPhoneId != VoiceContact.ID_UNDEFINED) { addCallIntent(intents, ContentUris.withAppendedId( Phone.CONTENT_URI, spokenPhoneId), - literal, commands[7], 0); + literal, spokenPhoneIdCommand, 0); count++; } } // 'CALL JACK JONES', with valid default phoneId - else if (commands.length == 7) { + else if (commands.length == PHONE_ID_COUNT + 1) { String phoneType = null; CharSequence phoneIdMsg = null; - if (phoneId == VoiceContact.ID_UNDEFINED) { + if (primaryId == VoiceContact.ID_UNDEFINED) { phoneType = null; phoneIdMsg = null; - } else if (phoneId == homeId) { + } else if (primaryId == homeId) { phoneType = "H"; phoneIdMsg = res.getText(R.string.at_home); - } else if (phoneId == mobileId) { + } else if (primaryId == mobileId) { phoneType = "M"; phoneIdMsg = res.getText(R.string.on_mobile); - } else if (phoneId == workId) { + } else if (primaryId == workId) { phoneType = "W"; phoneIdMsg = res.getText(R.string.at_work); - } else if (phoneId == otherId) { + } else if (primaryId == otherId) { phoneType = "O"; phoneIdMsg = res.getText(R.string.at_other); } if (phoneIdMsg != null) { addCallIntent(intents, ContentUris.withAppendedId( - Phone.CONTENT_URI, phoneId), + Phone.CONTENT_URI, primaryId), literal + phoneIdMsg, phoneType, 0); count++; } @@ -1042,7 +1054,7 @@ public class CommandRecognizerEngine extends RecognizerEngine { // trim last two words, ie 'at home', etc String lit = literal; - if (commands.length == 8) { + if (commands.length == PHONE_ID_COUNT + 2) { String[] words = literal.trim().split(" "); StringBuffer sb = new StringBuffer(); for (int i = 0; i < words.length - 2; i++) { @@ -1085,25 +1097,13 @@ public class CommandRecognizerEngine extends RecognizerEngine { lit + res.getText(R.string.at_other), "O", 0); count++; } - } - // - // if no other entries were generated, use the personId - // - - // add 'CALL JACK JONES', with valid personId - if (count == 0 && contactId != VoiceContact.ID_UNDEFINED) { - // TODO: what should really happen here is, we find - // all phones for this contact, and create a label that - // says "call person X at phone type Y", and add intents - // for each of them to the return list. - // It's too late in <del>Gingerbread</del> ICS to add the strings that - // would be required for this, so we'll just ignore this person. - // See also issue 3090362 and 5551677 - - // ACTION_CALL_PRIVILEGED does not work with Contacts.CONTENT_URI. - // addCallIntent(intents, ContentUris.withAppendedId( - // Contacts.CONTENT_URI, contactId), literal, "", 0); + if (fallbackId != VoiceContact.ID_UNDEFINED) { + addCallIntent(intents, ContentUris.withAppendedId( + Phone.CONTENT_URI, fallbackId), + lit, "", 0); + count++; + } } } @@ -1206,10 +1206,10 @@ public class CommandRecognizerEngine extends RecognizerEngine { // only add if different private static void addCallIntent(ArrayList<Intent> intents, Uri uri, String literal, String phoneType, int flags) { - Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri). - setFlags(flags). - putExtra(SENTENCE_EXTRA, literal). - putExtra(PHONE_TYPE_EXTRA, phoneType); + Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri) + .setFlags(flags) + .putExtra(SENTENCE_EXTRA, literal) + .putExtra(PHONE_TYPE_EXTRA, phoneType); addIntent(intents, intent); } } diff --git a/src/com/android/voicedialer/VoiceContact.java b/src/com/android/voicedialer/VoiceContact.java index 477d619..5bb0ba7 100644 --- a/src/com/android/voicedialer/VoiceContact.java +++ b/src/com/android/voicedialer/VoiceContact.java @@ -49,6 +49,10 @@ public class VoiceContact { public final long mMobileId; public final long mWorkId; public final long mOtherId; + /** + * Id for a phone number which doesn't belong to any other ids stored above. + */ + public final long mFallbackId; /** * Constructor. @@ -62,7 +66,7 @@ public class VoiceContact { * @param otherId other ID in phone table. */ private VoiceContact(String name, long contactId, long primaryId, - long homeId, long mobileId, long workId,long otherId) { + long homeId, long mobileId, long workId, long otherId, long fallbackId) { mName = name; mContactId = contactId; mPrimaryId = primaryId; @@ -70,6 +74,7 @@ public class VoiceContact { mMobileId = mobileId; mWorkId = workId; mOtherId = otherId; + mFallbackId = fallbackId; } @Override @@ -82,6 +87,7 @@ public class VoiceContact { hash = LARGE_PRIME * (hash + (int)mMobileId); hash = LARGE_PRIME * (hash + (int)mWorkId); hash = LARGE_PRIME * (hash + (int)mOtherId); + hash = LARGE_PRIME * (hash + (int)mFallbackId); return mName.hashCode() + hash; } @@ -93,7 +99,8 @@ public class VoiceContact { + " mHomeId=" + mHomeId + " mMobileId=" + mMobileId + " mWorkId=" + mWorkId - + " mOtherId=" + mOtherId; + + " mOtherId=" + mOtherId + + " mFallbackId=" + mFallbackId; } /** @@ -121,7 +128,9 @@ public class VoiceContact { Cursor cursor = activity.getContentResolver().query( Phone.CONTENT_URI, phonesProjection, Phone.NUMBER + " NOT NULL", null, - Phone.LAST_TIME_CONTACTED + " DESC, " + Phone.DISPLAY_NAME + " ASC"); + Phone.LAST_TIME_CONTACTED + " DESC, " + + Phone.DISPLAY_NAME + " ASC, " + + Phone._ID + " DESC"); final int phoneIdColumn = cursor.getColumnIndexOrThrow(Phone._ID); final int typeColumn = cursor.getColumnIndexOrThrow(Phone.TYPE); @@ -138,6 +147,7 @@ public class VoiceContact { long mobileId = ID_UNDEFINED; long workId = ID_UNDEFINED; long otherId = ID_UNDEFINED; + long fallbackId = ID_UNDEFINED; // loop over phone table for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { @@ -163,7 +173,7 @@ public class VoiceContact { // encountered a new name, so generate current VoiceContact if (name != null && !name.equals(nameAtCursor)) { contacts.add(new VoiceContact(name, personId, primaryId, - homeId, mobileId, workId, otherId)); + homeId, mobileId, workId, otherId, fallbackId)); name = null; } @@ -176,6 +186,7 @@ public class VoiceContact { mobileId = ID_UNDEFINED; workId = ID_UNDEFINED; otherId = ID_UNDEFINED; + fallbackId = ID_UNDEFINED; } // if labeled, then patch to HOME/MOBILE/WORK/OTHER @@ -196,6 +207,7 @@ public class VoiceContact { } } + boolean idAtCursorWasUsed = false; // save the home, mobile, or work phone id switch (typeAtCursor) { case Phone.TYPE_HOME: @@ -203,32 +215,40 @@ public class VoiceContact { if (isPrimaryAtCursor != 0) { primaryId = phoneIdAtCursor; } + idAtCursorWasUsed = true; break; case Phone.TYPE_MOBILE: mobileId = phoneIdAtCursor; if (isPrimaryAtCursor != 0) { primaryId = phoneIdAtCursor; } + idAtCursorWasUsed = true; break; case Phone.TYPE_WORK: workId = phoneIdAtCursor; if (isPrimaryAtCursor != 0) { primaryId = phoneIdAtCursor; } + idAtCursorWasUsed = true; break; case Phone.TYPE_OTHER: otherId = phoneIdAtCursor; if (isPrimaryAtCursor != 0) { primaryId = phoneIdAtCursor; } + idAtCursorWasUsed = true; break; } + + if (fallbackId == ID_UNDEFINED && !idAtCursorWasUsed) { + fallbackId = phoneIdAtCursor; + } } // generate the last VoiceContact if (name != null) { contacts.add(new VoiceContact(name, personId, primaryId, - homeId, mobileId, workId, otherId)); + homeId, mobileId, workId, otherId, fallbackId)); } // clean up cursor @@ -256,7 +276,7 @@ public class VoiceContact { String name; for (int id = 1; (name = br.readLine()) != null; id++) { contacts.add(new VoiceContact(name, id, ID_UNDEFINED, - ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED)); + ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED, ID_UNDEFINED)); } } catch (IOException e) { |