FileDocCategorySizeDatePackage
RecognizerLogger.javaAPI DocAndroid 1.5 API8413Wed May 06 22:42:48 BST 2009com.android.voicedialer

RecognizerLogger.java

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * 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 com.android.voicedialer;

import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.speech.srec.WaveHeader;
import android.text.format.DateFormat;
import android.util.Config;
import android.util.Log;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * This class logs the inputs and results of a recognition session to
 * the files listed below, which reside in
 * /data/data/com.android.voicedialer/app_logdir.
 * The files have the date encoded in the  name so that they will sort in
 * time order.  The newest RecognizerLogger.MAX_FILES are kept,
 * and the rest deleted to limit space used in the file system.
 * <ul>
 * <li> datename.wav - what the microphone heard.
 * <li> datename.log - contact list, results, errors, etc.
 * </ul>
 */
public class RecognizerLogger {

    private static final String TAG = "RecognizerLogger";
    
    private static final String LOGDIR = "logdir";
    private static final String ENABLED = "enabled";
    
    private static final int MAX_FILES = 20;
    
    private final String mDatedPath;
    private final BufferedWriter mWriter;
    
    /**
     * Determine if logging is enabled.  If the
     * @param context needed to reference the logging directory.
     * @return true if logging is enabled, determined by the 'enabled' file.
     */
    public static boolean isEnabled(Context context) {
        File dir = context.getDir(LOGDIR, 0);
        File enabled = new File(dir, ENABLED);
        return enabled.exists();
    }
    
    /**
     * Enable logging.
     * @param context needed to reference the logging directory.
     */
    public static void enable(Context context) {
        try {
            File dir = context.getDir(LOGDIR, 0);
            File enabled = new File(dir, ENABLED);
            enabled.createNewFile();
        }
        catch (IOException e) {
            Log.e(TAG, "enableLogging " + e);
        }
    }
    
    /**
     * Disable logging.
     * @param context needed to reference the logging directory.
     */
    public static void disable(Context context) {
        try {
            File dir = context.getDir(LOGDIR, 0);
            File enabled = new File(dir, ENABLED);
            enabled.delete();
        }
        catch (SecurityException e) {
            Log.e(TAG, "disableLogging " + e);
        }
    }

    /**
     * Constructor
     * @param dataDir directory to contain the log files.
     */
    public RecognizerLogger(Context context) throws IOException {
        if (Config.LOGD) Log.d(TAG, "RecognizerLogger");
        
        // generate new root filename
        File dir = context.getDir(LOGDIR, 0);
        mDatedPath = dir.toString() + File.separator + "log_" +
                DateFormat.format("yyyy_MM_dd_kk_mm_ss",
                        System.currentTimeMillis());
        
        // delete oldest files
        deleteOldest(".wav");
        deleteOldest(".log");
        
        // generate new text output log file
        mWriter = new BufferedWriter(new FileWriter(mDatedPath + ".log"), 8192);
        mWriter.write(Build.FINGERPRINT);
        mWriter.newLine();
    }
    
    /**
     * Write a line into the text log file.
     */
    public void logLine(String msg) {
        try {
            mWriter.write(msg);
            mWriter.newLine();
        }
        catch (IOException e) {
            Log.e(TAG, "logLine exception: " + e);
        }
    }
    
    /**
     * Write a header for the NBest lines into the text log file.
     */
    public void logNbestHeader() {
        logLine("Nbest *****************");
    }
    
    /**
     * Write the list of contacts into the text log file.
     * @param contacts
     */
    public void logContacts(List<VoiceContact> contacts) {
        logLine("Contacts *****************");
        for (VoiceContact vc : contacts) logLine(vc.toString());
        try {
            mWriter.flush();
        }
        catch (IOException e) {
            Log.e(TAG, "logContacts exception: " + e);
        }
    }
    
    /**
     * Write a list of Intents into the text log file.
     * @param intents
     */
    public void logIntents(ArrayList<Intent> intents) {
        logLine("Intents *********************");
        StringBuffer sb = new StringBuffer();
        for (Intent intent : intents) {
            logLine(intent.toString() + " " + RecognizerEngine.SENTENCE_EXTRA + "=" +
                    intent.getStringExtra(RecognizerEngine.SENTENCE_EXTRA));
        }
        try {
            mWriter.flush();
        }
        catch (IOException e) {
            Log.e(TAG, "logIntents exception: " + e);
        }
    }
    
    /**
     * Close the text log file.
     * @throws IOException
     */
    public void close() throws IOException {
        mWriter.close();
    }

    /**
     * Delete oldest files with a given suffix, if more than MAX_FILES.
     * @param suffix delete oldest files with this suffix.
     */
    private void deleteOldest(final String suffix) {
        FileFilter ff = new FileFilter() {
            public boolean accept(File f) {
                String name = f.getName();
                return name.startsWith("log_") && name.endsWith(suffix);
            }
        };
        File[] files = (new File(mDatedPath)).getParentFile().listFiles(ff);
        Arrays.sort(files);

        for (int i = 0; i < files.length - MAX_FILES; i++) {
            files[i].delete();            
        }
    }

    /**
     * InputStream wrapper which will log the contents to a WAV file.
     * @param inputStream
     * @param sampleRate
     * @return
     */
    public InputStream logInputStream(final InputStream inputStream, final int sampleRate) {
        final ByteArrayOutputStream baos = new ByteArrayOutputStream(sampleRate * 2 * 20);
        
        return new InputStream() {

            public int available() throws IOException {
                return inputStream.available();
            }

            public int read(byte[] b, int offset, int length) throws IOException {
                int rtn = inputStream.read(b, offset, length);
                if (rtn > 0) baos.write(b, offset, rtn);
                return rtn;
            }

            public int read(byte[] b) throws IOException {
                int rtn = inputStream.read(b);
                if (rtn > 0) baos.write(b, 0, rtn);
                return rtn;
            }

            public int read() throws IOException {
                int rtn = inputStream.read();
                if (rtn > 0) baos.write(rtn);
                return rtn;
            }

            public long skip(long n) throws IOException {
                throw new UnsupportedOperationException();
            }

            public void close() throws IOException {
                try {
                    OutputStream out = new FileOutputStream(mDatedPath + ".wav");
                    try {
                        byte[] pcm = baos.toByteArray();
                        WaveHeader hdr = new WaveHeader(WaveHeader.FORMAT_PCM,
                                (short)1, sampleRate, (short)16, pcm.length);
                        hdr.write(out);
                        out.write(pcm);
                    }
                    finally {
                        out.close();
                    }
                }
                finally {
                    inputStream.close();
                    baos.close();
                }
            }
        };
    }

}