]>
Commit | Line | Data |
---|---|---|
f9a162a2 TB |
1 | /* |
2 | * Copyright (C) 2012 Tobias Brunner | |
3 | * Hochschule fuer Technik Rapperswil | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License as published by the | |
7 | * Free Software Foundation; either version 2 of the License, or (at your | |
8 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
12 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 | * for more details. | |
14 | */ | |
15 | ||
16 | package org.strongswan.android.ui; | |
17 | ||
18 | import java.io.BufferedReader; | |
19 | import java.io.File; | |
20 | import java.io.FileNotFoundException; | |
21 | import java.io.FileReader; | |
22 | import java.io.StringReader; | |
23 | ||
24 | import org.strongswan.android.R; | |
25 | import org.strongswan.android.logic.CharonVpnService; | |
26 | ||
27 | import android.app.Fragment; | |
28 | import android.os.Bundle; | |
ae10e8c4 | 29 | import android.os.FileObserver; |
f9a162a2 TB |
30 | import android.os.Handler; |
31 | import android.view.LayoutInflater; | |
32 | import android.view.View; | |
33 | import android.view.ViewGroup; | |
34 | import android.widget.TextView; | |
35 | ||
36 | public class LogFragment extends Fragment implements Runnable | |
37 | { | |
38 | private String mLogFilePath; | |
39 | private Handler mLogHandler; | |
40 | private TextView mLogView; | |
41 | private LogScrollView mScrollView; | |
42 | private BufferedReader mReader; | |
43 | private Thread mThread; | |
44 | private volatile boolean mRunning; | |
ae10e8c4 | 45 | private FileObserver mDirectoryObserver; |
f9a162a2 TB |
46 | |
47 | @Override | |
48 | public void onCreate(Bundle savedInstanceState) | |
49 | { | |
50 | super.onCreate(savedInstanceState); | |
51 | ||
52 | mLogFilePath = getActivity().getFilesDir() + File.separator + CharonVpnService.LOG_FILE; | |
53 | /* use a handler to update the log view */ | |
54 | mLogHandler = new Handler(); | |
ae10e8c4 TB |
55 | |
56 | mDirectoryObserver = new LogDirectoryObserver(getActivity().getFilesDir().getAbsolutePath()); | |
f9a162a2 TB |
57 | } |
58 | ||
59 | @Override | |
60 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) | |
61 | { | |
62 | View view = inflater.inflate(R.layout.log_fragment, null); | |
63 | mLogView = (TextView)view.findViewById(R.id.log_view); | |
64 | mScrollView = (LogScrollView)view.findViewById(R.id.scroll_view); | |
65 | return view; | |
66 | } | |
67 | ||
68 | @Override | |
69 | public void onStart() | |
70 | { | |
71 | super.onStart(); | |
ae10e8c4 TB |
72 | startLogReader(); |
73 | mDirectoryObserver.startWatching(); | |
74 | } | |
75 | ||
76 | @Override | |
77 | public void onStop() | |
78 | { | |
79 | super.onStop(); | |
80 | mDirectoryObserver.stopWatching(); | |
81 | stopLogReader(); | |
82 | } | |
83 | ||
84 | /** | |
85 | * Start reading from the log file | |
86 | */ | |
87 | private void startLogReader() | |
88 | { | |
f9a162a2 TB |
89 | try |
90 | { | |
91 | mReader = new BufferedReader(new FileReader(mLogFilePath)); | |
92 | } | |
93 | catch (FileNotFoundException e) | |
94 | { | |
95 | mReader = new BufferedReader(new StringReader("")); | |
96 | } | |
ae10e8c4 TB |
97 | |
98 | mLogView.setText(""); | |
f9a162a2 TB |
99 | mRunning = true; |
100 | mThread = new Thread(this); | |
101 | mThread.start(); | |
102 | } | |
103 | ||
ae10e8c4 TB |
104 | /** |
105 | * Stop reading from the log file | |
106 | */ | |
107 | private void stopLogReader() | |
f9a162a2 | 108 | { |
f9a162a2 TB |
109 | try |
110 | { | |
111 | mRunning = false; | |
112 | mThread.interrupt(); | |
113 | mThread.join(); | |
114 | } | |
115 | catch (InterruptedException e) | |
116 | { | |
117 | } | |
118 | } | |
119 | ||
120 | /** | |
121 | * Write the given log line to the TextView. We strip the prefix off to save | |
122 | * some space (it is not that helpful for regular users anyway). | |
ae10e8c4 | 123 | * |
f9a162a2 TB |
124 | * @param line log line to log |
125 | */ | |
126 | public void logLine(final String line) | |
127 | { | |
128 | mLogHandler.post(new Runnable() { | |
129 | @Override | |
130 | public void run() | |
131 | { | |
132 | /* strip off prefix (month=3, day=2, time=8, thread=2, spaces=3) */ | |
133 | mLogView.append((line.length() > 18 ? line.substring(18) : line) + '\n'); | |
134 | /* calling autoScroll() directly does not work, probably because content | |
135 | * is not yet updated, so we post this to be done later */ | |
136 | mScrollView.post(new Runnable() { | |
137 | @Override | |
138 | public void run() | |
139 | { | |
140 | mScrollView.autoScroll(); | |
141 | } | |
142 | }); | |
143 | } | |
144 | }); | |
145 | } | |
146 | ||
147 | @Override | |
148 | public void run() | |
149 | { | |
150 | while (mRunning) | |
151 | { | |
152 | try | |
ae10e8c4 | 153 | { /* this works as long as the file is not truncated */ |
f9a162a2 TB |
154 | String line = mReader.readLine(); |
155 | if (line == null) | |
156 | { /* wait until there is more to log */ | |
157 | Thread.sleep(1000); | |
158 | } | |
159 | else | |
160 | { | |
161 | logLine(line); | |
162 | } | |
163 | } | |
164 | catch (Exception e) | |
165 | { | |
166 | break; | |
167 | } | |
168 | } | |
169 | } | |
ae10e8c4 TB |
170 | |
171 | /** | |
172 | * FileObserver that checks for changes regarding the log file. Since charon | |
173 | * truncates it (for which there is no explicit event) we check for any modification | |
174 | * to the file, keep track of the file size and reopen it if it got smaller. | |
175 | */ | |
176 | private class LogDirectoryObserver extends FileObserver | |
177 | { | |
178 | private final File mFile; | |
179 | private long mSize; | |
180 | ||
181 | public LogDirectoryObserver(String path) | |
182 | { | |
183 | super(path, FileObserver.CREATE | FileObserver.MODIFY | FileObserver.DELETE); | |
184 | mFile = new File(mLogFilePath); | |
185 | mSize = mFile.length(); | |
186 | } | |
187 | ||
188 | @Override | |
189 | public void onEvent(int event, String path) | |
190 | { | |
191 | if (path == null || !path.equals(CharonVpnService.LOG_FILE)) | |
192 | { | |
193 | return; | |
194 | } | |
195 | switch (event) | |
196 | { /* even though we only subscribed for these we check them, | |
197 | * as strange events are sometimes received */ | |
198 | case FileObserver.CREATE: | |
199 | case FileObserver.DELETE: | |
200 | restartLogReader(); | |
201 | break; | |
202 | case FileObserver.MODIFY: | |
203 | /* if the size got smaller reopen the log file, as it was probably truncated */ | |
204 | long size = mFile.length(); | |
205 | if (size < mSize) | |
206 | { | |
207 | restartLogReader(); | |
208 | } | |
209 | mSize = size; | |
210 | break; | |
211 | } | |
212 | } | |
213 | ||
214 | private void restartLogReader() | |
215 | { | |
216 | /* we are called from a separate thread, so we use the handler */ | |
217 | mLogHandler.post(new Runnable() { | |
218 | @Override | |
219 | public void run() | |
220 | { | |
221 | stopLogReader(); | |
222 | startLogReader(); | |
223 | } | |
224 | }); | |
225 | } | |
226 | } | |
f9a162a2 | 227 | } |