/* * Copyright 2011 Greg Milette and Adam Stroud * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package root.gast.speech.activation; import root.gast.R; import android.annotation.SuppressLint; import android.app.Notification; import android.app.PendingIntent; import android.app.Service; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.IBinder; import android.util.Log; /** * Persistently run a speech activator in the background. * Use {@link Intent}s to start and stop it * @author Greg Milette <<a * href="mailto:gregorym@gmail.com">gregorym@gmail.com</a>> * */ public class SpeechActivationService extends Service implements SpeechActivationListener { private static final String TAG = "SpeechActivationService"; public static final String NOTIFICATION_ICON_RESOURCE_INTENT_KEY = "NOTIFICATION_ICON_RESOURCE_INTENT_KEY"; public static final String ACTIVATION_TYPE_INTENT_KEY = "ACTIVATION_TYPE_INTENT_KEY"; public static final String ACTIVATION_RESULT_INTENT_KEY = "ACTIVATION_RESULT_INTENT_KEY"; public static final String ACTIVATION_RESULT_BROADCAST_NAME = "root.gast.playground.speech.ACTIVATION"; /** * send this when external code wants the Service to stop */ public static final String ACTIVATION_STOP_INTENT_KEY = "ACTIVATION_STOP_INTENT_KEY"; public static final int NOTIFICATION_ID = 10298; private boolean isStarted; private SpeechActivator activator; @Override public void onCreate() { super.onCreate(); isStarted = false; } public static Intent makeStartServiceIntent(Context context, String activationType) { Intent i = new Intent(context, SpeechActivationService.class); i.putExtra(ACTIVATION_TYPE_INTENT_KEY, activationType); return i; } public static Intent makeServiceStopIntent(Context context) { Intent i = new Intent(context, SpeechActivationService.class); i.putExtra(ACTIVATION_STOP_INTENT_KEY, true); return i; } /** * stop or start an activator based on the activator type and if an * activator is currently running */ @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { if (intent.hasExtra(ACTIVATION_STOP_INTENT_KEY)) { Log.d(TAG, "stop service intent"); activated(false); } else { if (isStarted) { // the activator is currently started // if the intent is requesting a new activator // stop the current activator and start // the new one if (isDifferentType(intent)) { Log.d(TAG, "is differnet type"); stopActivator(); startDetecting(intent); } else { Log.d(TAG, "already started this type"); } } else { // activator not started, start it startDetecting(intent); } } } // restart in case the Service gets canceled return START_REDELIVER_INTENT; } private void startDetecting(Intent intent) { Log.d(TAG, "extras: " + intent.getExtras().toString()); if (activator == null) { Log.d(TAG, "null activator"); } activator = getRequestedActivator(intent); Log.d(TAG, "started: " + activator.getClass().getSimpleName()); isStarted = true; activator.detectActivation(); startForeground(NOTIFICATION_ID, getNotification(intent)); } private SpeechActivator getRequestedActivator(Intent intent) { String type = intent.getStringExtra(ACTIVATION_TYPE_INTENT_KEY); // create based on a type name SpeechActivator speechActivator = SpeechActivatorFactory.createSpeechActivator(this, this, type); return speechActivator; } /** * determine if the intent contains an activator type * that is different than the currently running type */ private boolean isDifferentType(Intent intent) { boolean different = false; if (activator == null) { return true; } else { SpeechActivator possibleOther = getRequestedActivator(intent); different = !(possibleOther.getClass().getName(). equals(activator.getClass().getName())); } return different; } @Override public void activated(boolean success) { // make sure the activator is stopped before doing anything else stopActivator(); // broadcast result Intent intent = new Intent(ACTIVATION_RESULT_BROADCAST_NAME); intent.putExtra(ACTIVATION_RESULT_INTENT_KEY, success); sendBroadcast(intent); // always stop after receive an activation stopSelf(); } @Override public void onDestroy() { Log.d(TAG, "On destroy"); super.onDestroy(); stopActivator(); stopForeground(true); } private void stopActivator() { if (activator != null) { Log.d(TAG, "stopped: " + activator.getClass().getSimpleName()); activator.stop(); isStarted = false; } } @SuppressLint("NewApi") private Notification getNotification(Intent intent) { // determine label based on the class String name = SpeechActivatorFactory.getLabel(this, activator); String message = getString(R.string.speech_activation_notification_listening) + " " + name; String title = getString(R.string.speech_activation_notification_title); PendingIntent pi = PendingIntent.getService(this, 0, makeServiceStopIntent(this), 0); int icon = intent.getIntExtra(NOTIFICATION_ICON_RESOURCE_INTENT_KEY, R.drawable.icon); Notification notification; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { Notification.Builder builder = new Notification.Builder(this); builder.setSmallIcon(icon) .setWhen(System.currentTimeMillis()).setTicker(message) .setContentTitle(title).setContentText(message) .setContentIntent(pi); notification = builder.getNotification(); } else { notification = new Notification(icon, message, System.currentTimeMillis()); notification.setLatestEventInfo(this, title, message, pi); } return notification; } @Override public IBinder onBind(Intent intent) { return null; } }