• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.voicedialer;
18 
19 import android.content.Context;
20 import android.content.Intent;
21 import android.os.Build;
22 import android.speech.srec.WaveHeader;
23 import android.text.format.DateFormat;
24 import android.util.Config;
25 import android.util.Log;
26 
27 import java.io.BufferedWriter;
28 import java.io.ByteArrayOutputStream;
29 import java.io.File;
30 import java.io.FileFilter;
31 import java.io.FileOutputStream;
32 import java.io.FileWriter;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.List;
39 
40 /**
41  * This class logs the inputs and results of a recognition session to
42  * the files listed below, which reside in
43  * /data/data/com.android.voicedialer/app_logdir.
44  * The files have the date encoded in the  name so that they will sort in
45  * time order.  The newest RecognizerLogger.MAX_FILES are kept,
46  * and the rest deleted to limit space used in the file system.
47  * <ul>
48  * <li> datename.wav - what the microphone heard.
49  * <li> datename.log - contact list, results, errors, etc.
50  * </ul>
51  */
52 public class RecognizerLogger {
53 
54     private static final String TAG = "RecognizerLogger";
55 
56     private static final String LOGDIR = "logdir";
57     private static final String ENABLED = "enabled";
58 
59     private static final int MAX_FILES = 20;
60 
61     private final String mDatedPath;
62     private final BufferedWriter mWriter;
63 
64     /**
65      * Determine if logging is enabled.  If the
66      * @param context needed to reference the logging directory.
67      * @return true if logging is enabled, determined by the 'enabled' file.
68      */
isEnabled(Context context)69     public static boolean isEnabled(Context context) {
70         File dir = context.getDir(LOGDIR, 0);
71         File enabled = new File(dir, ENABLED);
72         return enabled.exists();
73     }
74 
75     /**
76      * Enable logging.
77      * @param context needed to reference the logging directory.
78      */
enable(Context context)79     public static void enable(Context context) {
80         try {
81             File dir = context.getDir(LOGDIR, 0);
82             File enabled = new File(dir, ENABLED);
83             enabled.createNewFile();
84         }
85         catch (IOException e) {
86             Log.e(TAG, "enableLogging " + e);
87         }
88     }
89 
90     /**
91      * Disable logging.
92      * @param context needed to reference the logging directory.
93      */
disable(Context context)94     public static void disable(Context context) {
95         try {
96             File dir = context.getDir(LOGDIR, 0);
97             File enabled = new File(dir, ENABLED);
98             enabled.delete();
99         }
100         catch (SecurityException e) {
101             Log.e(TAG, "disableLogging " + e);
102         }
103     }
104 
105     /**
106      * Constructor
107      * @param dataDir directory to contain the log files.
108      */
RecognizerLogger(Context context)109     public RecognizerLogger(Context context) throws IOException {
110         if (Config.LOGD) Log.d(TAG, "RecognizerLogger");
111 
112         // generate new root filename
113         File dir = context.getDir(LOGDIR, 0);
114         mDatedPath = dir.toString() + File.separator + "log_" +
115                 DateFormat.format("yyyy_MM_dd_kk_mm_ss",
116                         System.currentTimeMillis());
117 
118         // delete oldest files
119         deleteOldest(".wav");
120         deleteOldest(".log");
121 
122         // generate new text output log file
123         mWriter = new BufferedWriter(new FileWriter(mDatedPath + ".log"), 8192);
124         mWriter.write(Build.FINGERPRINT);
125         mWriter.newLine();
126     }
127 
128     /**
129      * Write a line into the text log file.
130      */
logLine(String msg)131     public void logLine(String msg) {
132         try {
133             mWriter.write(msg);
134             mWriter.newLine();
135         }
136         catch (IOException e) {
137             Log.e(TAG, "logLine exception: " + e);
138         }
139     }
140 
141     /**
142      * Write a header for the NBest lines into the text log file.
143      */
logNbestHeader()144     public void logNbestHeader() {
145         logLine("Nbest *****************");
146     }
147 
148     /**
149      * Write the list of contacts into the text log file.
150      * @param contacts
151      */
logContacts(List<VoiceContact> contacts)152     public void logContacts(List<VoiceContact> contacts) {
153         logLine("Contacts *****************");
154         for (VoiceContact vc : contacts) logLine(vc.toString());
155         try {
156             mWriter.flush();
157         }
158         catch (IOException e) {
159             Log.e(TAG, "logContacts exception: " + e);
160         }
161     }
162 
163     /**
164      * Write a list of Intents into the text log file.
165      * @param intents
166      */
logIntents(ArrayList<Intent> intents)167     public void logIntents(ArrayList<Intent> intents) {
168         logLine("Intents *********************");
169         StringBuffer sb = new StringBuffer();
170         for (Intent intent : intents) {
171             logLine(intent.toString() + " " + RecognizerEngine.SENTENCE_EXTRA + "=" +
172                     intent.getStringExtra(RecognizerEngine.SENTENCE_EXTRA));
173         }
174         try {
175             mWriter.flush();
176         }
177         catch (IOException e) {
178             Log.e(TAG, "logIntents exception: " + e);
179         }
180     }
181 
182     /**
183      * Close the text log file.
184      * @throws IOException
185      */
close()186     public void close() throws IOException {
187         mWriter.close();
188     }
189 
190     /**
191      * Delete oldest files with a given suffix, if more than MAX_FILES.
192      * @param suffix delete oldest files with this suffix.
193      */
deleteOldest(final String suffix)194     private void deleteOldest(final String suffix) {
195         FileFilter ff = new FileFilter() {
196             public boolean accept(File f) {
197                 String name = f.getName();
198                 return name.startsWith("log_") && name.endsWith(suffix);
199             }
200         };
201         File[] files = (new File(mDatedPath)).getParentFile().listFiles(ff);
202         Arrays.sort(files);
203 
204         for (int i = 0; i < files.length - MAX_FILES; i++) {
205             files[i].delete();
206         }
207     }
208 
209     /**
210      * InputStream wrapper which will log the contents to a WAV file.
211      * @param inputStream
212      * @param sampleRate
213      * @return
214      */
logInputStream(final InputStream inputStream, final int sampleRate)215     public InputStream logInputStream(final InputStream inputStream, final int sampleRate) {
216         final ByteArrayOutputStream baos = new ByteArrayOutputStream(sampleRate * 2 * 20);
217 
218         return new InputStream() {
219 
220             public int available() throws IOException {
221                 return inputStream.available();
222             }
223 
224             public int read(byte[] b, int offset, int length) throws IOException {
225                 int rtn = inputStream.read(b, offset, length);
226                 if (rtn > 0) baos.write(b, offset, rtn);
227                 return rtn;
228             }
229 
230             public int read(byte[] b) throws IOException {
231                 int rtn = inputStream.read(b);
232                 if (rtn > 0) baos.write(b, 0, rtn);
233                 return rtn;
234             }
235 
236             public int read() throws IOException {
237                 int rtn = inputStream.read();
238                 if (rtn > 0) baos.write(rtn);
239                 return rtn;
240             }
241 
242             public long skip(long n) throws IOException {
243                 throw new UnsupportedOperationException();
244             }
245 
246             public void close() throws IOException {
247                 try {
248                     OutputStream out = new FileOutputStream(mDatedPath + ".wav");
249                     try {
250                         byte[] pcm = baos.toByteArray();
251                         WaveHeader hdr = new WaveHeader(WaveHeader.FORMAT_PCM,
252                                 (short)1, sampleRate, (short)16, pcm.length);
253                         hdr.write(out);
254                         out.write(pcm);
255                     }
256                     finally {
257                         out.close();
258                     }
259                 }
260                 finally {
261                     inputStream.close();
262                     baos.close();
263                 }
264             }
265         };
266     }
267 
268 }
269