Is it possible to save a logcat entry in a sqlite database?
If a user got an error I want to read the logs without having the phone connected to adb.
This is how I write logs: Log.d(TAG, "An error occured", e)
Thanks
Creating a log file will be better option to read error
public void mlogFile(String pActivityName, String pOperation, String pData) {
File lLogFilePath, lLogFile;
Date lDate;
CharSequence lCurrfolder;
FileWriter lFileWriter;
BufferedWriter lBuffWriter;
String lActivity, lOperation;
try {
lDate = new Date();
lCurrfolder = DateFormat.format("yyyyMMdd", lDate.getTime());
lLogFilePath = new File(Environment.getExternalStorageDirectory().getAbsolutePath(), "CSPDCLData/" + lCurrfolder + "/");
if (!lLogFilePath.exists()) {
lLogFilePath.mkdirs();
}
lLogFile = new File(lLogFilePath, "ADDLogfile.txt");
lFileWriter = new FileWriter(lLogFile, true);
lBuffWriter = new BufferedWriter(lFileWriter);
lActivity = pActivityName.length() != 0 ? ADDPadding(pActivityName, 25, ' ', 'L') + "~ " : "";
lOperation = pOperation.length() != 0 ? " : " + pData : "";
lBuffWriter.append(DateFormat.format("kk:mm:ss", lDate.getTime()) + " " + lActivity + pOperation + lOperation + "\n");
lBuffWriter.flush();
lBuffWriter.close();
lFileWriter.close();
} catch (IOException ex) {
Toast.makeText(this, "ERROR: " + ex.getMessage(), Toast.LENGTH_SHORT).show();
}
}
And at the time of error add this line
logFile(getClass().getSimpleName(),"methodName()", "An error occured"+ e.getMessage());
I have an app that reads notifications to the driver while driving. I am trying to parse the various notifications. Those that use the old 'tickerText' work fine but several apps like Skype don't support that. Instead, the text in the notification after the first message just says something like "3 new messages". Not very helpful. I want the last message string instead. I wrote this:
public class Catcher extends NotificationListenerService {
File file;
String dir;
File save;
int count = 0;
#Override
public void onCreate() {
super.onCreate();
dir = Environment.getExternalStorageDirectory() + "/NotCatch";
save = new File(dir);
if(!save.exists()){
save.mkdirs();
}
//Toast.makeText(this, dir + " " + file.getName(), Toast.LENGTH_LONG).show();
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
file = new File(save, "NotCatch" + count + ".txt");
count++;
String temp = "";
String[] lines;
Notification not = sbn.getNotification();
temp += "Category: " + not.category+ "\n";
temp+= "TickerText: " + not.tickerText + "\n";
temp += "Extras..."+ "\n";
Bundle bun = not.extras;
temp+= "BigText: " + bun.getString(Notification.EXTRA_BIG_TEXT)+ "\n";
temp+= "SummaryText: " + bun.getString(Notification.EXTRA_SUMMARY_TEXT)+ "\n";
temp+= "InfoText: " + bun.getString(Notification.EXTRA_INFO_TEXT)+ "\n";
temp+= "Text: " + bun.getString(Notification.EXTRA_TEXT)+ "\n";
temp+= "TextLines: " + bun.getString(Notification.EXTRA_TEXT_LINES)+ "\n";
temp+= "SubText: " + bun.getString(Notification.EXTRA_SUB_TEXT) + "\n";
temp+= "Title:" + bun.getString(Notification.EXTRA_TITLE) +"\n";
temp+= "Big Title:" + bun.getString(Notification.EXTRA_TITLE_BIG) +"\n";
/* lines = bun.getString(Notification.EXTRA_TEXT_LINES).split("\n");
temp += "Lines... \n" ;
int cnt = 0;
for (String line : lines) {
temp+= cnt + ": " + line + "\n";
cnt++;
}*/
Looper.prepare();
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(temp.getBytes());
fos.close();
Toast.makeText(this,"File written", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
}
This is just what I have so far for testing of course. I can get the bundle from the notification but it can't get the string array of the message lines. It looks like this in the debugger. 'bun' below is the 'Bundle' from the 'Notification'.
My question is this. How do I get the array of strings that start with "some message text - 4"? This is the bundle from an Android Notification.
I finally was able to get the strings this way
CharSequence[] lines = bun.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
for(CharSequence line : lines){
temp+= "line: " + line.toString() + "\n";
}
Since the strings you are trying to retrieve are contained in the ArrayMap mMap (according to the debugger image), and as implementations of Map are serializable, you'll want to do the following to first retrieve that map:
ArrayMap map = bun.getSerializableExtra("mMap");
Then, you should be able to get the array of strings you want (which according to the debugger image is an array of CharSequence objects) with the following:
CharSequence[] messages = (CharSequence[]) map.valueAt(1);
An interesting read on bundles and maps:
https://medium.com/the-wtf-files/the-mysterious-case-of-the-bundle-and-the-map-7b15279a794e#.kf3m2haa3
i would like to read the subject of a new received email (gmail) from an android notification.
I think i have to use a NotificationListenerService running in background, catch the notification of new email in real time, and read the subject from that.
But how can i read the subject or a part of body text? Is it possible?
Thank you very much.
Here is an example that catches notifications and puts them into a text file. I only made this for development purposes so I could see how each app populates the notifications but it should show you how to do it.
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
new Store().execute(sbn);
}
private class Store extends AsyncTask<StatusBarNotification, Integer, Long> {
#Override
protected Long doInBackground(StatusBarNotification... params) {
String temp = "";
StatusBarNotification sbn = params[0];
Notification not = sbn.getNotification();
String pack = sbn.getPackageName();
// dump all the android notifications
if (pack.startsWith("com.android")) return null;
if (pack.startsWith("com.estrongs")) return null;
if (pack.startsWith("com.motorola")) return null;
count++;
if (not.category != null)
temp += "Category: " + not.category.toString() + "\n";
else
temp += "Category = null \n";
if (not.tickerText != null)
temp += "TickerText: " + not.tickerText.toString() + "\n";
else
temp += "TickerText = null \n";
temp += "Key: " + sbn.getKey() + "\n" + "ID: " + sbn.getId() + "\n";
SimpleDateFormat format = new SimpleDateFormat("DD-kk:mm:ss:SSS");
Long ptime = sbn.getPostTime();
temp += "Post time: " + format.format(ptime) + "\n";
Long nottime = not.when;
temp += "When: " + format.format(nottime) + "\n";
temp += "Extras..." + "\n";
Bundle bun = not.extras;
if (bun.getString(Notification.EXTRA_BIG_TEXT) != null)
temp += "BigText: " + bun.getString(Notification.EXTRA_BIG_TEXT).toString() + "\n";
else
temp += "BigText = null \n";
if (bun.getString(Notification.EXTRA_SUMMARY_TEXT) != null)
temp += "SummaryText: " + bun.getString(Notification.EXTRA_SUMMARY_TEXT).toString() + "\n";
else
temp += "SummaryText = null \n";
if (bun.getString(Notification.EXTRA_INFO_TEXT) != null)
temp += "InfoText: " + bun.getString(Notification.EXTRA_INFO_TEXT).toString() + "\n";
else
temp += "InfoText = null \n";
if (bun.getString(Notification.EXTRA_TEXT) != null)
temp += "Text: " + bun.getString(Notification.EXTRA_TEXT).toString() + "\n";
else
temp += "Text = null \n";
if (bun.getString(Notification.EXTRA_SUB_TEXT) != null)
temp += "SubText: " + bun.getString(Notification.EXTRA_SUB_TEXT).toString() + "\n";
else
temp += "SubText = null \n";
if (bun.getString(Notification.EXTRA_TITLE) != null)
temp += "Title:" + bun.getString(Notification.EXTRA_TITLE).toString() + "\n";
else
temp += "Title = null \n";
if (bun.getString(Notification.EXTRA_TITLE_BIG) != null)
temp += "Big Title:" + bun.getString(Notification.EXTRA_TITLE_BIG).toString() + "\n";
else
temp += "Big Title = null \n";
temp += "Fields... \n";
CharSequence[] lines = bun.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
if (lines != null) {
for (CharSequence line : lines) {
temp += "line: " + line.toString() + " \n";
}
} else {
temp += " no lines... \n";
}
file = new File(save, pack + count + ".txt");
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(temp.getBytes());
fos.close();
//Toast.makeText(this, "File written", Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
//Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
//Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
}
return null;
}
}
Notice I send the SBN to a background thread. The listener does not like much of anything in its thread. Also, the listener can be tricky with the debugger. I found that you need to disable the app in Android settings -> Sound & Notification -> Notification Access before you update the app. Then you can re-enable it once a package update is installed.
Hope that helps.
I have been working with GSON to try and parse a Json response I am getting from a CakePHP server for about a week. Here is what the response looks like :
[{"BaseObject": {"field1":"1","field2":"1639","field3":"10","field4":"1","field5":"12","field6":"10.765984","field7":"-25.768357","field8":"1327790850"}},{"BaseObject":{"field1":"2","field2":"1934","field3":"19","field4":"30","field5":"2","field6":"10.758662","field7":"-25.769684","field8":"1327790850"}},{"BaseObject":{"field1":"3","field2":"2567","field3":"33","field4":"6","field5":"98","field6":"10.758786","field7":"-25.769843","field8":"1327790850"}},{"BaseObject":{"field1":"4","field2":"0","field3":"33","field4":"7","field5":"0","field6":"10.758786","field7":"-20.769843","field8":"1327790850"}},{"BaseObject":{"field1":"5","field2":"1097","field3":"33","field4":"1","field5":"0","field6":"15.758786","field7":"50.769843","field8":"1327790850"}},{"BaseObject":{"field1":"6","field2":"1936","field3":"50","field4":"0","field5":"9","field6":"19.234987","field7":"-67.340065","field8":"1327798560"}}]
I used a plugin for Notepad++ to verify that the response is valid Json and it is.
First I tried this function:
public static List<BaseObject> parserInputStreamGson(InputStream stream)
{
List<BaseObject> objList = new ArrayList<BaseObject>();
if(stream != null){
Gson gson = new Gson();
Reader r = new InputStreamReader(stream);
Log.d(TAG,"Trying to Parse Reader");
try{
objList = gson.fromJson(r, new TypeToken<List<BaseObject>>() {}.getType() );
} catch (JsonSyntaxException e) {
Log.d(TAG, "JsonSyntaxException : " + e.getMessage() );
} catch (JsonIOException e) {
Log.d(TAG, "JsonIOException : " + e.getMessage() );
} finally {
try {
r.close();
} catch (IOException e) {
Log.d(TAG, "IOException : " + e.getMessage() );
}
}
}
Log.d(TAG,"BaseObject[] = " + objList.toString());
return objList;
}
Then I tried this function:
public static BaseObject[] parserInputStreamGsonArray(InputStream stream)
{
BaseObject[] objectArray = null;
if (stream != null) {
Gson gson = new Gson();
Reader r = new InputStreamReader(stream);
Log.d(TAG, "Trying to Parse Reader");
try {
objectArray = gson.fromJson(r, new TypeToken<Event[]>() {}.getType());
} catch (JsonSyntaxException e) {
Log.d(TAG, "JsonSyntaxException : " + e.getMessage());
} catch (JsonIOException e) {
Log.d(TAG, "JsonIOException : " + e.getMessage());
} finally {
try {
r.close();
} catch (IOException e) {
Log.d(TAG, "IOException : " + e.getMessage());
}
}
}
if(eventArray != null){
for(int m=0;m<eventArray.length;m++){
Log.d(TAG, "objectArray[" + String.valueOf(m) + "] = " + objectArray[m].toString());
}
}
return objectArray;
}
And in both cases Gson returned 5 objects, but all of the fields were set to zero.
Finally I got this function to work, but it feels clunky.
public static List<BaseObject> ParseInputStream(InputStream stream) {
Reader r = new InputStreamReader(stream);
List<BaseObject> baseObjectList = new ArrayList<BaseObject>();
try {
JsonParser parser = new JsonParser();
JsonArray array = parser.parse(r).getAsJsonArray();
JsonObject topObject = new JsonObject();
JsonObject subObject = new JsonObject();
for (int m = 0; m < array.size(); m++) {
if (array.get(m).isJsonObject()) {
topObject = array.get(m).getAsJsonObject();
if (topObject.get("BaseObject").isJsonObject()) {
subObject = topObject.get("BaseObject").getAsJsonObject();
BaseObject baseobject = new BaseObject();
baseobject.field1 = subObject.get("field1").getAsLong();
baseobject.field2 = subObject.get("field2").getAsInt();
baseobject.field3 = subObject.get("field3").getAsLong();
baseobject.field4 = subObject.get("field4").getAsInt();
baseobject.field5 = subObject.get("field5").getAsInt();
baseobject.field6 = subObject.get("field6").getAsDouble();
baseobject.field7 = subObject.get("field7").getAsDouble();
baseobject.field8 = subObject.get("field8").getAsLong();
baseObjectList.add(baseobject);
} else {
Log.e(TAG, "topObject[" + String.valueOf(m)+ "].subObject is not a JsonObject");
}
} else {
Log.e(TAG, "Array # " + String.valueOf(m)+ " is not a JsonObject!");
}
}
} catch (Exception ex) {
Log.e(TAG, "Exception thrown = " + ex.toString());
ex.printStackTrace();
}
return baseObjectList;
}
Here is the class I created for BaseObject.
public class BaseObject {
#SerializedName("field1")
public long field1;
#SerializedName("field2")
public int field2;
#SerializedName("field3")
public long field3;
#SerializedName("field4")
public int field4;
#SerializedName("field5")
public int field5;
#SerializedName("field6")
public double field6;
#SerializedName("field7")
public double field7;
#SerializedName("field8")
public long field8;
#Override
public String toString() {
return "(" +
"field1= " + String.valueOf(this.field1) + ", " +
"field2= " + String.valueOf(this.field2) + ", " +
"field3= " + String.valueOf(this.field3) + ", " +
"field4= " + String.valueOf(this.field4) + ", " +
"field5= " + String.valueOf(this.field5) + ", " +
"field6= " + String.valueOf(this.field6) + ", " +
"field7= " + String.valueOf(this.field7) + ", " +
"field8= " + String.valueOf(this.field8) +
")";
}
}
Can anyone tell me how I need to structure my data classes in order use Gson.fromJson to work.
Since your response is actually List<BaseObject>, you should be using
List baseObjectList = new Gson().fromJson(r,new TypeToken>() {}.getType())
Also I should mention that, you do not really need to use the #SerializedName annotations since your attribute names in the json reply and in the class are same.
UPDATE:
Oops.. Sorry, I should have tried your code before answering. Please refer to the following code. Everything boiled down to the Structuring of classes.
public class Sample {
public static class Wrapper{
private BaseObject BaseObject;
#Override
public String toString() {
return BaseObject == null? null : BaseObject.toString();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String json = "[{\"BaseObject\": {\"field1\":\"1\",\"field2\":\"1639\",\"field3\":\"10\",\"field4\":\"1\",\"field5\":\"12\",\"field6\":\"10.765984\",\"field7\":\"-25.768357\",\"field8\":\"1327790850\"}},{\"BaseObject\":{\"field1\":\"2\",\"field2\":\"1934\",\"field3\":\"19\",\"field4\":\"30\",\"field5\":\"2\",\"field6\":\"10.758662\",\"field7\":\"-25.769684\",\"field8\":\"1327790850\"}},{\"BaseObject\":{\"field1\":\"3\",\"field2\":\"2567\",\"field3\":\"33\",\"field4\":\"6\",\"field5\":\"98\",\"field6\":\"10.758786\",\"field7\":\"-25.769843\",\"field8\":\"1327790850\"}},{\"BaseObject\":{\"field1\":\"4\",\"field2\":\"0\",\"field3\":\"33\",\"field4\":\"7\",\"field5\":\"0\",\"field6\":\"10.758786\",\"field7\":\"-20.769843\",\"field8\":\"1327790850\"}},{\"BaseObject\":{\"field1\":\"5\",\"field2\":\"1097\",\"field3\":\"33\",\"field4\":\"1\",\"field5\":\"0\",\"field6\":\"15.758786\",\"field7\":\"50.769843\",\"field8\":\"1327790850\"}},{\"BaseObject\":{\"field1\":\"6\",\"field2\":\"1936\",\"field3\":\"50\",\"field4\":\"0\",\"field5\":\"9\",\"field6\":\"19.234987\",\"field7\":\"-67.340065\",\"field8\":\"1327798560\"}}]";
List<Wrapper> results = new Gson().fromJson(json,new TypeToken<List<Wrapper>>(){}.getType());
System.out.println(results);
}
}
Just curious, do you have the liberty to change the JSON reply coming from server? IMHO, Its structure is a little complicated.
I am working on an android application. In which i have slideShows. I am parsing these through an xml and after parsing them, saving in the SQLite DB. Majority of the slideshows are saved properly but, sometimes this happens that the slides are saved two times that is, every slide in the slideShow is saved two times obviously with different PK but same content. which should be avoided.
Partial code is here, where i am getting the slides and trying to store them in DB.
ArrayList<SlideShowItem> slideItems = null;
slideItems=Utils.database.getSlideItemOfUrl(Constants.StoriesTable,tempSlideShow.getFullStoryUrl().substring(0, index - 1), type);
if (slideItems == null) {
Log.d("store in DB: ", " when SlideItems == null ");
Log.d("SlideShow Title: ", tempSlideShow.getTitle());
Log.d("SlideShow pub Date: ", tempSlideShow.getPubDate());
slideItems = tempSlideShow.getSlideShow();
Utils.database.storeSlideItem(Constants.StoriesTable, myUrl,slideItems, type);
Utils.topStorySlidesArrayList = slideItems;
slideItems = null ;
} else {
Log.d("SlideShow Title: ", tempSlideShow.getTitle());
Utils.topStorySlidesArrayList = slideItems;
slideItems = null ;
}
and code of function storeSlideItem in DataBase is:
public synchronized void storeSlideItem(String tableName, String, url,ArrayList<SlideShowItem> list, String type) {
System.out.println("size of the Array list: " + list.size());
String newType = null;
if (type == null) {
newType = "List";
}else{
newType = type;
}
ArrayList<SlideShowItem> newList = new ArrayList<SlideShowItem>();
//newList = null;
Iterator<SlideShowItem> iterator = list.iterator();
while (iterator.hasNext())
{
SlideShowItem sSItem = iterator.next();
if(!newList.contains(sSItem))
{
newList.add(sSItem);
}
}
try {
for (int i = 0; i < newList.size(); i++) {
SlideShowItem item = newList.get(i);
String itemUrl = url + i;// Unique URL for the DB;
String imgString = null;
Log.e("Loop Counter", " time " + i);
Drawable drawable = item.getImage();
if (item.getBody() != null) {
item.setBody(item.getBody().replace('\'', '`'));
// replace as it create syntax error for storing data
}
if (item.getSubTitle() != null) {
item.setSubTitle(item.getSubTitle().replace('\'', '`'));
}
if (drawable != null) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
imgString = Base64.encodeBytes(b);
}
if (isOpen()) {
myDB.execSQL("INSERT INTO " + tableName + "(" + column[1] + "," + column[2] + "," + column[3] + "," + column[4] + "," + column[6]
+ "," + column[7] + ",type) VALUES('" + itemUrl + "','" + item.getSubTitle() + "','" + item.getBody() + "','"
+ item.getImagePath() + "','" + item.getIndex() + "','" + imgString + "','" + newType + "Slide')");
if (item.getBody() != null) {
item.setBody(item.getBody().replace('`', '\''));// " ' "
// replace as it create syntax error for storing data
}
if (item.getSubTitle() != null) {
item.setSubTitle(item.getSubTitle().replace('`', '\''));
}
if (tableName.equals(Constants.StoriesTable)) {
item.setItemId(getItemID(tableName, itemUrl));
Utils.hashListStoriesIds.put(itemUrl, item.getItemId());
if (imgString != null) {
Utils.hashListImages.put(item.getItemId(), new Boolean(true));
} else {
Utils.hashListImages.put(item.getItemId(), new Boolean(false));
}
}
}
}
} catch (Exception e) {
Log.e("Error", "Exception: storeSlideItem type " + e.toString());
} finally {
closeConnection();
}
}
Please tell me anything that can get me out of this irritating problem. Any help is appreciated.
in DB for duplication of slides the view is somewhat like:
1 abc USA 111
2 abc USA 111
and so on this was for one slide of a slideShow. if i have 3 slides in a slideshow, i'll get 6 entries in DB each slide being saved for two times.
Use HashSet instead of ArrayList