1/*
2** Copyright 2007, 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
17package com.android.development;
18
19import static com.android.internal.util.CharSequences.forAsciiBytes;
20
21import java.io.DataInputStream;
22import java.io.IOException;
23import java.io.FileOutputStream;
24import java.net.Socket;
25
26import android.app.Activity;
27import android.os.Handler;
28import android.os.Bundle;
29import android.util.Log;
30import android.graphics.Typeface;
31import android.view.Gravity;
32
33/**
34 * Views the device log.
35 */
36public class LogViewer extends Activity {
37
38    static final String TAG = LogViewer.class.getSimpleName();
39
40    FileOutputStream logger;
41
42    volatile boolean active = true;
43    Handler handler;
44    LogTextBox text;
45
46    @Override
47    protected void onCreate(Bundle icicle) {
48        super.onCreate(icicle);
49        setContentView(R.layout.log_viewer);
50        this.handler = new Handler();
51
52        text = (LogTextBox) findViewById(R.id.text);
53
54        text.setTextSize(10);
55        text.setHorizontallyScrolling(true);
56        text.setTypeface(Typeface.MONOSPACE);
57        text.setGravity(Gravity.BOTTOM | Gravity.LEFT);
58
59        this.active = true;
60        try {
61            logger = new FileOutputStream("/tmp/logviewer.txt");
62            new Thread(new LogReader()).start();
63        } catch (IOException e) {
64            appendThrowable(e);
65        }
66    }
67
68    private void appendThrowable(Throwable t) {
69        StringBuilder builder = new StringBuilder();
70        builder.append("Error reading log: ");
71        builder.append(Log.getStackTraceString(t));
72        text.getText().append(builder);
73    }
74
75    private class LogReader implements Runnable {
76
77        final Socket socket;
78        final DataInputStream in;
79        StringBuilder builder = new StringBuilder();
80        long lastTime = System.currentTimeMillis();
81
82        private static final int HEADER_SIZE = 24;
83
84        public LogReader() throws IOException {
85            this.socket = new Socket("127.0.0.1", 5040);
86            this.in = new DataInputStream(this.socket.getInputStream());
87            // Write two newlines to indicate "no reader args"
88            this.socket.getOutputStream().write('\n');
89            this.socket.getOutputStream().write('\n');
90        }
91
92        public void run() {
93            while (active) {
94                try {
95                    while (in.available() > 0) {
96                        logger.write("Reading message.\n".getBytes());
97
98                        int length = in.readInt();
99                        byte[] bytes = new byte[length];
100                        in.readFully(bytes);
101
102                        int tagEnd = next0(bytes, HEADER_SIZE);
103                        int fileEnd = next0(bytes, tagEnd + 1);
104                        int messageEnd = next0(bytes, fileEnd + 1);
105
106                        CharSequence tag
107                                = forAsciiBytes(bytes, HEADER_SIZE, tagEnd);
108                        CharSequence message
109                                = forAsciiBytes(bytes, fileEnd + 1, messageEnd);
110
111                        builder.append(tag)
112                                .append(": ")
113                                .append(message)
114                                .append("\n");
115                    }
116
117                    logger.write("Updating UI.\n".getBytes());
118                    handler.post(new AppendCharacters(builder));
119                    builder = new StringBuilder();
120
121                    try {
122                        Thread.sleep(1000);
123                    } catch (InterruptedException e) {}
124                } catch (final IOException e) {
125                    handler.post(new AppendThrowable(e));
126                }
127            }
128        }
129    }
130
131    static int next0(byte[] bytes, int start) {
132        for (int current = start; current < bytes.length; current++) {
133            if (bytes[current] == 0)
134                return current;
135        }
136        return bytes.length;
137    }
138
139    private class AppendThrowable implements Runnable {
140
141        private final Throwable t;
142
143        public AppendThrowable(Throwable t) {
144            this.t = t;
145        }
146
147        public void run() {
148            appendThrowable(t);
149        }
150    }
151
152    private class AppendCharacters implements Runnable {
153
154        private final CharSequence message;
155
156        public AppendCharacters(CharSequence message) {
157            this.message = message;
158        }
159
160        public void run() {
161            text.getText().append(message);
162//            try {
163//                logger.write(builder.toString().getBytes());
164//            } catch (IOException e) {
165//                appendThrowable(e);
166//            }
167        }
168    }
169}
170