/* * Copyright (C) 2014 Fastboot Mobile, LLC. * * This program is free software; you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program; * if not, see <http://www.gnu.org/licenses>. */ package com.fastbootmobile.encore.voice; import android.content.Context; import android.content.res.Resources; import com.fastbootmobile.encore.app.R; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * */ public class VoiceCommander { private static final String TAG = "VoiceCommander"; public static final int ACTION_PLAY_ALBUM = 1; public static final int ACTION_PLAY_ARTIST = 2; public static final int ACTION_PLAY_PLAYLIST = 3; public static final int ACTION_PLAY_TRACK = 4; public static final int EXTRA_SOURCE = 1; public static final int ACTION_PAUSE = 5; public static final int ACTION_NEXT = 6; public static final int EXTRA_TIME_SECS = 2; public static final int EXTRA_TIME_MINS = 3; public static final int ACTION_JUMP = 7; public static final int ACTION_PREVIOUS = 8; public static final int ACTION_GOOGLE = 9; private final List<Pattern> mPlayPlaylistPatterns = new ArrayList<>(); private final List<Pattern> mPlayPlaylistSourcePatterns = new ArrayList<>(); private final List<Pattern> mPlayArtistPatterns = new ArrayList<>(); private final List<Pattern> mPlayArtistSourcePatterns = new ArrayList<>(); private final List<Pattern> mPlayAlbumPatterns = new ArrayList<>(); private final List<Pattern> mPlayAlbumSourcePatterns = new ArrayList<>(); private final List<Pattern> mPlayTrackPatterns = new ArrayList<>(); private final List<Pattern> mPlayTrackSourcePatterns = new ArrayList<>(); private final List<Pattern> mPausePatterns = new ArrayList<>(); private final List<Pattern> mJumpPatterns = new ArrayList<>(); private final List<Pattern> mNextPatterns = new ArrayList<>(); private final List<Pattern> mNextPatternsTimeSecs = new ArrayList<>(); private final List<Pattern> mNextPatternsTimeMins = new ArrayList<>(); private final List<Pattern> mPreviousPatterns = new ArrayList<>(); private final List<Pattern> mPreviousPatternsTimeSecs = new ArrayList<>(); private final List<Pattern> mPreviousPatternsTimeMins = new ArrayList<>(); private final List<Pattern> mGooglePatterns = new ArrayList<>(); public VoiceCommander(Context context) { Resources res = context.getResources(); String[] playWords = res.getStringArray(R.array.voice_play_words); String[] playSourceWords = res.getStringArray(R.array.voice_play_source_words); String[] playArtistWords = res.getStringArray(R.array.voice_play_artist_words); String[] playAlbumWords = res.getStringArray(R.array.voice_play_album_words); String[] playPlaylistWords = res.getStringArray(R.array.voice_play_playlist_words); String[] playSongWords = res.getStringArray(R.array.voice_play_track_words); String[] pauseWords = res.getStringArray(R.array.voice_pause_words); String[] nextWords = res.getStringArray(R.array.voice_next_words); String[] jumpWords = res.getStringArray(R.array.voice_jump_words); String[] previousWords = res.getStringArray(R.array.voice_previous_words); String[] timeSeconds = res.getStringArray(R.array.voice_time_seconds); String[] timeMinutes = res.getStringArray(R.array.voice_time_minutes); String[] googleWords = res.getStringArray(R.array.voice_google_words); // Pre-compile patterns Pattern pattern; // Play patterns for (String playWord : playWords) { // Play (without source) patterns for (String artistWord : playArtistWords) { pattern = Pattern.compile("^" + playWord + " " + artistWord + " (.*?)$", Pattern.CASE_INSENSITIVE); mPlayArtistPatterns.add(pattern); } for (String albumWord : playAlbumWords) { pattern = Pattern.compile("^" + playWord + " " + albumWord + " (.*?)$", Pattern.CASE_INSENSITIVE); mPlayAlbumPatterns.add(pattern); } for (String playlistWord : playPlaylistWords) { pattern = Pattern.compile("^" + playWord + " " + playlistWord + " (.*?)$", Pattern.CASE_INSENSITIVE); mPlayPlaylistPatterns.add(pattern); } for (String trackWord : playSongWords) { pattern = Pattern.compile("^" + playWord + " " + trackWord + " (.*?)$", Pattern.CASE_INSENSITIVE); mPlayTrackPatterns.add(pattern); } /* // Play (with source) patterns for (String sourceWord : playSourceWords) { pattern = Pattern.compile("^" + playWord + " (.*?) " + sourceWord + " (.*?)$", Pattern.CASE_INSENSITIVE); mPlaySourcePatterns.add(pattern); }*/ } // Pause patterns for (String pauseWord : pauseWords) { pattern = Pattern.compile("^" + pauseWord + "$", Pattern.CASE_INSENSITIVE); mPausePatterns.add(pattern); } // Jump patterns for (String jumpWord : jumpWords) { pattern = Pattern.compile("^" + jumpWord + " ([0-9]+)$", Pattern.CASE_INSENSITIVE); mJumpPatterns.add(pattern); } // Next patterns for (String nextWord : nextWords) { pattern = Pattern.compile("^" + nextWord + "$", Pattern.CASE_INSENSITIVE); mNextPatterns.add(pattern); for (String time : timeSeconds) { pattern = Pattern.compile("^" + nextWord + " ([0-9]+) " + time + "$", Pattern.CASE_INSENSITIVE); mNextPatternsTimeSecs.add(pattern); } for (String time : timeMinutes) { pattern = Pattern.compile("^" + nextWord + " ([0-9]+) " + time + "$", Pattern.CASE_INSENSITIVE); mNextPatternsTimeMins.add(pattern); } } // Previous patterns for (String previousWord : previousWords) { pattern = Pattern.compile("^" + previousWord + "$", Pattern.CASE_INSENSITIVE); mPreviousPatterns.add(pattern); for (String time : timeSeconds) { pattern = Pattern.compile("^" + previousWord + " ([0-9]+) " + time + "$", Pattern.CASE_INSENSITIVE); mPreviousPatternsTimeSecs.add(pattern); } for (String time : timeMinutes) { pattern = Pattern.compile("^" + previousWord + " ([0-9]+) " + time + "$", Pattern.CASE_INSENSITIVE); mPreviousPatternsTimeMins.add(pattern); } } // Google patterns for (String googleWord : googleWords) { pattern = Pattern.compile("^" + googleWord + " (.*?)$", Pattern.CASE_INSENSITIVE); mGooglePatterns.add(pattern); } } public boolean processResult(List<String> results, ResultListener listener) { for (String line : results) { // We're going to try to match each sentence, longest first for each prefix Matcher matcher; // Play with source /* for (Pattern playSourcePattern : mPlaySourcePatterns) { matcher = playSourcePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PLAY, EXTRA_SOURCE, new String[]{matcher.group(1), matcher.group(2)}); return true; } }*/ // Play without source for (Pattern playSourcePattern : mPlayTrackPatterns) { matcher = playSourcePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PLAY_TRACK, 0, new String[]{matcher.group(1)}); return true; } } for (Pattern playSourcePattern : mPlayPlaylistPatterns) { matcher = playSourcePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PLAY_PLAYLIST, 0, new String[]{matcher.group(1)}); return true; } } for (Pattern playSourcePattern : mPlayArtistPatterns) { matcher = playSourcePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PLAY_ARTIST, 0, new String[]{matcher.group(1)}); return true; } } for (Pattern playSourcePattern : mPlayAlbumPatterns) { matcher = playSourcePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PLAY_ALBUM, 0, new String[]{matcher.group(1)}); return true; } } // Pause for (Pattern pausePattern : mPausePatterns) { matcher = pausePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PAUSE, 0, null); return true; } } // Jump to ... for (Pattern jumpPattern : mJumpPatterns) { matcher = jumpPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_JUMP, 0, new String[]{matcher.group(1)}); return true; } } // Skip xx seconds for (Pattern nextSecsPattern : mNextPatternsTimeSecs) { matcher = nextSecsPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_NEXT, EXTRA_TIME_SECS, new String[]{matcher.group(1)}); return true; } } // Skip xx minutes for (Pattern nextMinsPattern : mNextPatternsTimeMins) { matcher = nextMinsPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_NEXT, EXTRA_TIME_MINS, new String[]{matcher.group(1)}); return true; } } // Next for (Pattern nextPattern : mNextPatterns) { matcher = nextPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_NEXT, 0, null); return true; } } // Previous xx seconds for (Pattern previousSecsPattern : mPreviousPatternsTimeSecs) { matcher = previousSecsPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PREVIOUS, EXTRA_TIME_SECS, new String[]{matcher.group(1)}); return true; } } // Previous xx minutes for (Pattern previousMinsPattern : mPreviousPatternsTimeMins) { matcher = previousMinsPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PREVIOUS, EXTRA_TIME_MINS, new String[]{matcher.group(1)}); return true; } } // Previous for (Pattern previousPattern : mPreviousPatterns) { matcher = previousPattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_PREVIOUS, 0, null); return true; } } // Google for (Pattern googlePattern : mGooglePatterns) { matcher = googlePattern.matcher(line); if (matcher.matches()) { listener.onResult(ACTION_GOOGLE, 0, new String[]{matcher.group(1)}); return true; } } } return false; } public interface ResultListener { public void onResult(int action, int extra, String[] params); } }