Home | History | Annotate | Download | only in voice
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package com.android.inputmethod.deprecated.voice;
     18 
     19 import com.android.common.speech.LoggingEvents;
     20 import com.android.inputmethod.deprecated.compat.VoiceInputLoggerCompatUtils;
     21 
     22 import android.content.Context;
     23 import android.content.Intent;
     24 
     25 /**
     26  * Provides the logging facility for voice input events. This fires broadcasts back to
     27  * the voice search app which then logs on our behalf.
     28  *
     29  * Note that debug console logging does not occur in this class. If you want to
     30  * see console output of these logging events, there is a boolean switch to turn
     31  * on on the VoiceSearch side.
     32  */
     33 public class VoiceInputLogger {
     34     @SuppressWarnings("unused")
     35     private static final String TAG = VoiceInputLogger.class.getSimpleName();
     36 
     37     private static VoiceInputLogger sVoiceInputLogger;
     38 
     39     private final Context mContext;
     40 
     41     // The base intent used to form all broadcast intents to the logger
     42     // in VoiceSearch.
     43     private final Intent mBaseIntent;
     44 
     45     // This flag is used to indicate when there are voice events that
     46     // need to be flushed.
     47     private boolean mHasLoggingInfo = false;
     48 
     49     /**
     50      * Returns the singleton of the logger.
     51      *
     52      * @param contextHint a hint context used when creating the logger instance.
     53      * Ignored if the singleton instance already exists.
     54      */
     55     public static synchronized VoiceInputLogger getLogger(Context contextHint) {
     56         if (sVoiceInputLogger == null) {
     57             sVoiceInputLogger = new VoiceInputLogger(contextHint);
     58         }
     59         return sVoiceInputLogger;
     60     }
     61 
     62     public VoiceInputLogger(Context context) {
     63         mContext = context;
     64 
     65         mBaseIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT);
     66         mBaseIntent.putExtra(LoggingEvents.EXTRA_APP_NAME, LoggingEvents.VoiceIme.APP_NAME);
     67     }
     68 
     69     private Intent newLoggingBroadcast(int event) {
     70         Intent i = new Intent(mBaseIntent);
     71         i.putExtra(LoggingEvents.EXTRA_EVENT, event);
     72         return i;
     73     }
     74 
     75     public void flush() {
     76         if (hasLoggingInfo()) {
     77             Intent i = new Intent(mBaseIntent);
     78             i.putExtra(LoggingEvents.EXTRA_FLUSH, true);
     79             mContext.sendBroadcast(i);
     80             setHasLoggingInfo(false);
     81         }
     82     }
     83 
     84     public void keyboardWarningDialogShown() {
     85         setHasLoggingInfo(true);
     86         mContext.sendBroadcast(newLoggingBroadcast(
     87                 LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_SHOWN));
     88     }
     89 
     90     public void keyboardWarningDialogDismissed() {
     91         setHasLoggingInfo(true);
     92         mContext.sendBroadcast(newLoggingBroadcast(
     93                 LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_DISMISSED));
     94     }
     95 
     96     public void keyboardWarningDialogOk() {
     97         setHasLoggingInfo(true);
     98         mContext.sendBroadcast(newLoggingBroadcast(
     99                 LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_OK));
    100     }
    101 
    102     public void keyboardWarningDialogCancel() {
    103         setHasLoggingInfo(true);
    104         mContext.sendBroadcast(newLoggingBroadcast(
    105                 LoggingEvents.VoiceIme.KEYBOARD_WARNING_DIALOG_CANCEL));
    106     }
    107 
    108     public void settingsWarningDialogShown() {
    109         setHasLoggingInfo(true);
    110         mContext.sendBroadcast(newLoggingBroadcast(
    111                 LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_SHOWN));
    112     }
    113 
    114     public void settingsWarningDialogDismissed() {
    115         setHasLoggingInfo(true);
    116         mContext.sendBroadcast(newLoggingBroadcast(
    117                 LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_DISMISSED));
    118     }
    119 
    120     public void settingsWarningDialogOk() {
    121         setHasLoggingInfo(true);
    122         mContext.sendBroadcast(newLoggingBroadcast(
    123                 LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_OK));
    124     }
    125 
    126     public void settingsWarningDialogCancel() {
    127         setHasLoggingInfo(true);
    128         mContext.sendBroadcast(newLoggingBroadcast(
    129                 LoggingEvents.VoiceIme.SETTINGS_WARNING_DIALOG_CANCEL));
    130     }
    131 
    132     public void swipeHintDisplayed() {
    133         setHasLoggingInfo(true);
    134         mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.SWIPE_HINT_DISPLAYED));
    135     }
    136 
    137     public void cancelDuringListening() {
    138         setHasLoggingInfo(true);
    139         mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_LISTENING));
    140     }
    141 
    142     public void cancelDuringWorking() {
    143         setHasLoggingInfo(true);
    144         mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_WORKING));
    145     }
    146 
    147     public void cancelDuringError() {
    148         setHasLoggingInfo(true);
    149         mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.CANCEL_DURING_ERROR));
    150     }
    151 
    152     public void punctuationHintDisplayed() {
    153         setHasLoggingInfo(true);
    154         mContext.sendBroadcast(newLoggingBroadcast(
    155                 LoggingEvents.VoiceIme.PUNCTUATION_HINT_DISPLAYED));
    156     }
    157 
    158     public void error(int code) {
    159         setHasLoggingInfo(true);
    160         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.ERROR);
    161         i.putExtra(LoggingEvents.VoiceIme.EXTRA_ERROR_CODE, code);
    162         mContext.sendBroadcast(i);
    163     }
    164 
    165     public void start(String locale, boolean swipe) {
    166         setHasLoggingInfo(true);
    167         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.START);
    168         i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_LOCALE, locale);
    169         i.putExtra(LoggingEvents.VoiceIme.EXTRA_START_SWIPE, swipe);
    170         i.putExtra(LoggingEvents.EXTRA_TIMESTAMP, System.currentTimeMillis());
    171         mContext.sendBroadcast(i);
    172     }
    173 
    174     public void voiceInputDelivered(int length) {
    175         setHasLoggingInfo(true);
    176         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.VOICE_INPUT_DELIVERED);
    177         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
    178         mContext.sendBroadcast(i);
    179     }
    180 
    181     public void textModifiedByTypingInsertion(int length) {
    182         setHasLoggingInfo(true);
    183         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
    184         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
    185         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
    186                 LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_TYPING_INSERTION);
    187         mContext.sendBroadcast(i);
    188     }
    189 
    190     public void textModifiedByTypingInsertionPunctuation(int length) {
    191         setHasLoggingInfo(true);
    192         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
    193         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
    194         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
    195                 LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_TYPING_INSERTION_PUNCTUATION);
    196         mContext.sendBroadcast(i);
    197     }
    198 
    199     public void textModifiedByTypingDeletion(int length) {
    200         setHasLoggingInfo(true);
    201         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
    202         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
    203         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
    204                 LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_TYPING_DELETION);
    205 
    206         mContext.sendBroadcast(i);
    207     }
    208 
    209 
    210     public void textModifiedByChooseSuggestion(int suggestionLength, int replacedPhraseLength,
    211                                                int index, String before, String after) {
    212         setHasLoggingInfo(true);
    213         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
    214         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, suggestionLength);
    215         i.putExtra(VoiceInputLoggerCompatUtils.EXTRA_TEXT_REPLACED_LENGTH, replacedPhraseLength);
    216         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
    217                 LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_CHOOSE_SUGGESTION);
    218         i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index);
    219         i.putExtra(VoiceInputLoggerCompatUtils.EXTRA_BEFORE_N_BEST_CHOOSE, before);
    220         i.putExtra(VoiceInputLoggerCompatUtils.EXTRA_AFTER_N_BEST_CHOOSE, after);
    221         mContext.sendBroadcast(i);
    222     }
    223 
    224     public void inputEnded() {
    225         setHasLoggingInfo(true);
    226         mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.INPUT_ENDED));
    227     }
    228 
    229     public void voiceInputSettingEnabled() {
    230         setHasLoggingInfo(true);
    231         mContext.sendBroadcast(newLoggingBroadcast(
    232                 LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_ENABLED));
    233     }
    234 
    235     public void voiceInputSettingDisabled() {
    236         setHasLoggingInfo(true);
    237         mContext.sendBroadcast(newLoggingBroadcast(
    238                 LoggingEvents.VoiceIme.VOICE_INPUT_SETTING_DISABLED));
    239     }
    240 
    241     private void setHasLoggingInfo(boolean hasLoggingInfo) {
    242         mHasLoggingInfo = hasLoggingInfo;
    243         // If applications that call UserHappinessSignals.userAcceptedImeText
    244         // make that call after VoiceInputLogger.flush() calls this method with false, we
    245         // will lose those happiness signals. For example, consider the gmail sequence:
    246         // 1. compose message
    247         // 2. speak message into message field
    248         // 3. type subject into subject field
    249         // 4. press send
    250         // We will NOT get the signal that the user accepted the voice inputted message text
    251         // because when the user tapped on the subject field, the ime's flush will be triggered
    252         // and the hasLoggingInfo will be then set to false. So by the time the user hits send
    253         // we have essentially forgotten about any voice input.
    254         // However the following (more common) use case is properly logged
    255         // 1. compose message
    256         // 2. type subject in subject field
    257         // 3. speak message in message field
    258         // 4. press send
    259         VoiceInputLoggerCompatUtils.setHasVoiceLoggingInfoCompat(hasLoggingInfo);
    260     }
    261 
    262     private boolean hasLoggingInfo(){
    263         return mHasLoggingInfo;
    264     }
    265 
    266 }
    267