Since Google analytics can raise many privacy concerns, I implemented an events logger.
My first idea is to track user's generated events into a logfile and then send them back to the server that will perform the analysis of data for the System Administrator and Application Engineers.
For the moment the idea is to instantiate the Logger into an Application or a Service class and use those elements onCreate and onDestroy to safely handle the LogFile.
The solution is quite simple:
Open file
Append to it every time an event is generated
Once the a MAX_NUM_LINES is reached, send the log to the server (possibly I'll zip the text file I am generating)
I wonder if there's anything already baked there in the wild I am unaware of that you might know (something like ACRA).
Every contribution will be appreciated.
Here my implementation.
However any better version is much appreciated.
The TSG objet is just a static class that I use as time manager.
Use the code and improve it as long as you repost / edit the modifications.
public class Logger {
private BufferedWriter logFile;
private String nameFile;
public int fileLines;
private File fTemp;
private timeStampGenerator TSG;
private int LOG_LINES_LIMIT = 100;
private Object mutex;
public enum EventType {
BUTTON_PRESSED,
PAGE_VIEWED,
LOADED_ACTIVITY,
GENERIC_EVENT
}
public Logger (String fileName) throws IOException {
nameFile = fileName;
createLogFile();
fileLines = countLines();
TSG = new timeStampGenerator();
// This is our mutex to access to the file
mutex = new Object();
}
public void createLogFile() throws IOException{
fTemp = new File (nameFile);
if (!fTemp.exists()) {
fTemp.createNewFile();
}
logFile = new BufferedWriter(new FileWriter(nameFile, true));
}
public void LogEvent(EventType event, String comment, String value) {
String line = "";
line += TSG.getTimestampMillis();
line += ",";
line += event.name();
line += ",";
if (comment != "") {
line += comment.replaceAll(",", ";");
} else {
line += " ";
}
line += ",";
if (value != "") {
line += value.replaceAll(",", ";");
} else {
line += " ";
}
line += "\n";
synchronized (mutex) {
try {
logFile.append(line);
} catch (IOException e) {
// Do wathever you want here
}
fileLines++;
}
}
public int countLines() //throws IOException
{
InputStream is;
try {
is = new BufferedInputStream(new FileInputStream(nameFile));
} catch (FileNotFoundException e1) {
//let's consider it an empty file
return 0;
}
int count = 0;
boolean empty = true;
try {
int readChars = 0;
byte[] c = new byte[1024];
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n')
++count;
}
}
} catch(IOException e) {
// Do wathever you want here
}
try {
is.close();
} catch (IOException e) {
// Do wathever you want here
}
return (count == 0 && !empty) ? 1 : count;
}
public boolean isLimitReached() {
return (fileLines >= LOG_LINES_LIMIT);
}
public void close () {
flush();
try {
logFile.close();
} catch (IOException e) {
// Do wathever you want here
}
}
/**
* clear the content of the file
*/
public void clearFile() {
synchronized (mutex) {
if ( fTemp.delete() ) {
try {
createLogFile();
} catch (IOException e1) {
// Do wathever you want here
}
}
}
}
/**
* Get the full content of the file
* #return the content
*/
public String getContent() {
StringBuffer fileData = new StringBuffer();
synchronized (mutex) {
try {
BufferedReader reader = new BufferedReader(new FileReader( nameFile ));
char[] buf = new char[1024];
int numRead = 0;
while ((numRead = reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
}
reader.close();
} catch (IOException e) {
// Do wathever you want here
}
}
return fileData.toString();
}
public void flush() {
try {
logFile.flush();
} catch (IOException e) {
// Do wathever you want here
}
}
}
Related
Tried this but got 0.0 and on physical device nothing found..
Any way to get cpu temperature in android
SensorManager mySensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor AmbientTemperatureSensor
= mySensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
if (AmbientTemperatureSensor != null) {
mySensorManager.registerListener(
AmbientTemperatureSensorListener,
AmbientTemperatureSensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
private final SensorEventListener AmbientTemperatureSensorListener
= new SensorEventListener() {
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_AMBIENT_TEMPERATURE) {
temperature = event.values[0];
Messages.sendMessage(getApplicationContext(),Float.toString(temperature));
}
}
};
public static float cpuTemperature()
{
Process process;
try {
process = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone0/temp");
process.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = reader.readLine();
if(line!=null) {
float temp = Float.parseFloat(line);
return temp / 1000.0f;
}else{
return 51.0f;
}
} catch (Exception e) {
e.printStackTrace();
return 0.0f;
}
}
You can find all the thermal values(temp and type) from this code (not only CPU temperature). And also remember that sys/class/thermal/thermal_zone0/temp not always point towards CPU temperature (in my case it was pointing towards battery temperature). Always use this code in background thread. I have tested it on real device as well as emulator and it was working fine.
public void thermal() {
String temp, type;
for (int i = 0; i < 29; i++) {
temp = thermalTemp(i);
if (!temp.contains("0.0")) {
type = thermalType(i);
if (type != null) {
System.out.println("ThermalValues "+type+" : "+temp+"\n");
}
}
}
}
public String thermalTemp(int i) {
Process process;
BufferedReader reader;
String line;
String t = null;
float temp = 0;
try {
process = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone" + i + "/temp");
process.waitFor();
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
line = reader.readLine();
if (line != null) {
temp = Float.parseFloat(line);
}
reader.close();
process.destroy();
if (!((int) temp == 0)) {
if ((int) temp > 10000) {
temp = temp / 1000;
} else if ((int) temp > 1000) {
temp = temp / 100;
} else if ((int) temp > 100) {
temp = temp / 10;
}
} else
t = "0.0";
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
public String thermalType(int i) {
Process process;
BufferedReader reader;
String line, type = null;
try {
process = Runtime.getRuntime().exec("cat sys/class/thermal/thermal_zone" + i + "/type");
process.waitFor();
reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
line = reader.readLine();
if (line != null) {
type = line;
}
reader.close();
process.destroy();
} catch (Exception e) {
e.printStackTrace();
}
return type;
}
Sample Output in Logcat (Image below is Real device output... On emulator it only showed the type battery and its temperature.) :
There is a system service for this kind of stuff
HardwarePropertiesManager that contain a method getDeviceTemperatures(int type, int source) which is available from Nougat
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
HardwarePropertiesManager hardwarePropertiesManager= (HardwarePropertiesManager) getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
float[] temp = hardwarePropertiesManager.getDeviceTemperatures(HardwarePropertiesManager.DEVICE_TEMPERATURE_CPU, HardwarePropertiesManager.TEMPERATURE_CURRENT);
}
Take a look to this :
https://developer.android.com/reference/android/os/HardwarePropertiesManager
I'm new to android so please help me out. I am trying to save my ToDoList in a file so that the next time I open it, all the items are reloaded
This is the code I have so far,
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
gson = new Gson();
try {
BufferedReader br = new BufferedReader(new FileReader("storage.json"));
Entry e = gson.fromJson(br, Entry.class);
Log.d("reading", e.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
}}
#Override
protected void onStop() {
super.onStop();
json = gson.toJson(mEntries);
Log.d("jsondata", json);
try {
file1 = new FileWriter("storage.json");
file1.write(json);
file1.flush();
file1.close();
} catch (IOException e) {
e.printStackTrace();
}
Entry.java
public class Entry {
String S;
boolean b;
public Entry(String S, boolean b) {
this.S = S;
this.b = b;
}
public String getS() {
return S;
}
public void setS(String S) {
this.S = S;
}
public void setB(boolean b) {
this.b = b;
}
public boolean isB() {
return b;
}
}
How do I proceed from here? In onCreate() I would like to check if the file exists and if yes, import data from file and display on screen.
Every android app has its own internal storage only that app can access, you can read from there or write to it.
In you case, you first want to check if you such file exist before creating one.
private String read(Context context, String fileName) {
try {
FileInputStream fis = context.openFileInput(fileName);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader bufferedReader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (FileNotFoundException fileNotFound) {
return null;
} catch (IOException ioException) {
return null;
}
}
private boolean create(Context context, String fileName, String jsonString){
String FILENAME = "storage.json";
try {
FileOutputStream fos = context.openFileOutput(fileName,Context.MODE_PRIVATE);
if (jsonString != null) {
fos.write(jsonString.getBytes());
}
fos.close();
return true;
} catch (FileNotFoundException fileNotFound) {
return false;
} catch (IOException ioException) {
return false;
}
}
public boolean isFilePresent(Context context, String fileName) {
String path = context.getFilesDir().getAbsolutePath() + "/" + fileName;
File file = new File(path);
return file.exists();
}
onCreate of the Activity, you can use do the following
boolean isFilePresent = isFilePresent(getActivity(), "storage.json");
if(isFilePresent) {
String jsonString = read(getActivity(), "storage.json");
//do the json parsing here and do the rest of functionality of app
} else {
boolean isFileCreated = create(getActivity, "storage.json", "{}");
if(isFileCreated) {
//proceed with storing the first todo or show ui
} else {
//show error or try again.
}
}
reference https://developer.android.com/guide/topics/data/data-storage.html#filesInternal
I need to update data from server every second. I create handle with AsyncTask, that repeats every second. This works, but about a minute it crushes with EOFException by reading from DataInputStream.
Handler
handler.postDelayed( new Runnable() {
#Override
public void run() {
tickListAdapter = new TickListAdapter(TickActivity.this,tickList);
tickListView.setAdapter(tickListAdapter);
AsyncTCPSend tcpSend= new AsyncTCPSend(address,serverPort, line);
tcpSend.execute();
Log.e(TAG,"update");
handler.postDelayed( this, 1000 );
}
},1000 );
AsyncTask
public class AsyncTCPSend extends AsyncTask<Void, Void, Void> {
String address;
int port;
String message;
String response=null;String lineRead = null;
Socket socket;
int count=1;
OutputStream os;
DataInputStream dis;
AsyncTCPSend(String addr, int p, String mes) {
address = addr;
port = p;
message = mes;
}
#Override
protected Void doInBackground(Void... params) {
socket = null;
try {
socket = new Socket(address, port);
os = socket.getOutputStream();
dis = new DataInputStream(socket.getInputStream());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
if (!isConnect){
if (connect()){
isConnect = true;
Log.e("CLIENT","now is connected");
getTick();
}
}
return null;
}
public boolean connect(){
try {
Log.e("CLIENT","CONNECTED");
String command = "AUTH_START";
byte[] queryBody = null;
queryBody = command.getBytes("UTF-16LE");
byte[] message = new byte[queryBody.length];
for (int i = 0; i < message.length; ++i)
os.write(message,0,message.length);
Log.e(TAG,"AUTH_START");
String srv = null;
srv = function();
if (srv != null){
if (srv.equals("Error")){
Log.e("CLIENT","Error");
return false;
} else {
String auth_answer = "AUTH_ANSWER";
byte[] authBody = auth_answer.getBytes("UTF-16LE");
Log.e(TAG,"AUTH_ANSWER");
os.write(authBody,0,authBody.length);
srv = function();
if (srv.equals("Error")){
Log.e("CLIENT","Error");
return false;
} else {
Log.e(TAG,"AUTH SUCCESS!!!");
return true;
}
}
} else {
return false;
}
}
catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public String getTick(){
String tick = "TICK";
try {
tickBody = tick.getBytes("UTF-16LE");
os.write(tickBody,0,tickBody.length);
String srv = function();
return srv;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
String function(){
String srv = null;
int len = 0;
try {
len = dis.readInt(); //EOFException is here!!!!
byte[] data = new byte[1024];
if (len > 0) {
dis.read(data, 0, data.length);
}
String out = new String(data,"UTF-16");
if (out.indexOf("Done")>0){
if (out.indexOf("STAT")>0 ||out.indexOf("AST")>0){
srv = out;
}
else {
srv = out.substring(out.indexOf("SRV")+9,out.indexOf("SRV")+41);
}
} else {
srv = "Error";
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return srv;
}
#Override
protected void onPostExecute(Void result) {
Log.e("CLIENT","onPostExecute");
super.onPostExecute(result);
}
}
}
Anybody know why appear EOFException about a minute? How to avoid?
P.S. To obtain the necessary information from the server, I must first pass authentication
Why this exception occurs?
According to Docs
Signals that an end of file or end of stream has been reached unexpectedly during input.
This exception is mainly used by data input streams to signal end of stream. Note that many other input operations return a special value on end of stream rather than throwing an exception.
look upon this answer
The problem was solved by changing the method. I added two threads for output and input inside AsyncTask
public class PreviewDownload extends AsyncTask<String, Void, String> {
public static final String TAG = "PreviewDownload";
public String inputPath = null;
public String outputFolder = null;
public IRIssue issue = null;
#Override
protected String doInBackground(String... parms) {
InputStream input = null;
OutputStream output = null;
HttpURLConnection connection = null;
issue = Broker.model.issueDataStore.getIRIssue(parms[0]);
outputFolder = IRConstant.issueFolder(issue.year, issue.month, issue.day, issue.pubKey);
try {
inputPath = IRConstant.downloadFile(issue.year, issue.month, issue.day, issue.pubKey, "preview", "0");
URL url = new URL(inputPath);
Log.d (TAG,"input: " + inputPath);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
if (connection.getResponseCode() != HttpURLConnection.HTTP_OK)
return null;
// return "Server returned HTTP " + connection.getResponseCode()
// + " " + connection.getResponseMessage();
// download the file
input = connection.getInputStream();
output = new FileOutputStream(outputFolder + "/preview.zip");
Log.d (TAG,"output: " + output);
byte data[] = new byte[1024];
int count;
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
} catch (Exception e) {
// return e.toString();
return null;
} finally {
try {
if (output != null)
output.close();
if (input != null)
input.close();
} catch (IOException ignored) {
}
if (connection != null)
connection.disconnect();
}
return outputFolder;
}
#Override
protected void onPostExecute(String outputFolder) {
// TODO Auto-generated method stub
super.onPostExecute(outputFolder);
if (outputFolder != null) {
File zipFile = new File (outputFolder + "/preview.zip");
if (Utils.unzip(outputFolder,outputFolder + "/preview.zip" )) {
zipFile.delete();
issue.isThumbDownloaded = 1;
} else {
issue.isThumbDownloaded = 0;
}
} else {
Toast.makeText(Broker.launcherActivity.getBaseContext(), R.string.wordCantDownload, Toast.LENGTH_LONG).show();
issue.isThumbDownloaded = 0;
}
issue.updateProgress(issue.progress);
}
}
Here is the downloader I implemented , the problem is , when the network lost, the output become null and show error message, however, if I would like to retry two times before showing error message, are there any way to do this? If I perfer not to pass in an object instead of string ,is it not recommended? thanks
What prevents you from re-instanciating and re-executing a "Downloader" from your catch blocks in case of errors ?
You could use a single common shared object between dowloader instances to count the attempts, or better, pass a parameter to each of them. In the catch block, you would then retry if you didn't reach the limit, and increase the value passed to a new downloader... Something recursive.
int expectedLength = connection.getContentLength();
can you compare with the expectedLength & downloaded length and retry?
I'm programming a little game and I want to save on sd-card the scores and the the volume (enabled or disabled)
the code of my two functions is:
public static void load(FileIO files) {
BufferedReader in = null;
try {
in = new BufferedReader(new InputStreamReader(
files.readFile(".save")));
soundEnabled = Boolean.parseBoolean(in.readLine());
for (int i = 0; i < 5; i++) {
highscores[i] = Integer.parseInt(in.readLine());
}
} catch (IOException e) {
// :( It's ok we have defaults
} catch (NumberFormatException e) {
// :/ It's ok, defaults save our day
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
}
//-----------------------
public static void save(FileIO files) {
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
files.writeFile(".save")));
out.write(Boolean.toString(soundEnabled));
for (int i = 0; i < 5; i++) {
out.write(Integer.toString(highscores[i]));
}
} catch (IOException e) {
} finally {
try {
if (out != null)
out.close();
} catch (IOException e) {
}
}
}
while the program is running this code is ok but if I restart my device the scores are lost..
do you know why?
thanks!!
ps: the FileIO class is:
public class AndroidFileIO implements FileIO {
Context context;
AssetManager assets;
String externalStoragePath;
public AndroidFileIO(Context context) {
this.context = context;
this.assets = context.getAssets();
this.externalStoragePath = Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator;
}
public InputStream readAsset(String fileName) throws IOException {
return assets.open(fileName);
}
public InputStream readFile(String fileName) throws IOException {
return new FileInputStream(externalStoragePath + fileName);
}
public OutputStream writeFile(String fileName) throws IOException {
return new FileOutputStream(externalStoragePath + fileName);
}
public SharedPreferences getPreferences() {
return PreferenceManager.getDefaultSharedPreferences(context);
}
}
There are two problems here. First, out.write does not insert a newline at the end of each call, you have to do that manually. So what is happening is when you do the readline in the cal to parse the Boolean you are actually consuming ALL the data in the file. Second, you need to flush and close the file before leaving that function to be sure you do not leave any data in the buffers.
Here is save rewritten that should work:
public static void save(FileIO files) {
BufferedWriter out = null;
try {
out = new BufferedWriter(new OutputStreamWriter(
files.writeFile(".mrnom")));
out.write(Boolean.toString(soundEnabled));
out.write("\n");
for (int i = 0; i < 5; i++) {
out.write(Integer.toString(highscores[i]));
out.write("\n");
}
out.flush();
out.close();
} catch (IOException e) {
} finally {
try {
if (out != null)
out.close();
} catch (IOException e) {
}
}
}
I'm proggraming for first time but iv solved this using shared prefs. That way you avoid losing data when updating the app.