Get context in cordova plugin - android

Hi I'm using this GCM notification plugin for android and works almost perfect, the only issue I have is when the user force close my app or when the device is shutted down the notification service stops working.
I've looked the plugin code problem and realized that the following function causes the problem.
public static void sendJavascript( JSONObject _json )
{
String _d = "javascript:"+gECB+"(" + _json.toString() + ")";
Log.v(ME + ":sendJavascript", _d);
if (gECB != null ) {
gwebView.sendJavascript( _d );
}
}
When the device is shutted down and then turned on or the application is force closed, gwebView reference is lost. If I try to use the method gwebView.sendJavascript( _d ) I get a null pointer exception.
Reviewing the plugin code I noticed that gwebView is referenced when registering the device just as this code shows:
public static Plugin gwebView;
private static String gECB;
private static String gSenderID;
#SuppressWarnings("deprecation")
#Override
public PluginResult execute(String action, JSONArray data, String callbackId)
{
PluginResult result = null;
Log.v(ME + ":execute", "action=" + action);
if (REGISTER.equals(action)) {
Log.v(ME + ":execute", "data=" + data.toString());
try {
JSONObject jo= new JSONObject(data.toString().substring(1, data.toString().length()-1));
gwebView = this;
..............................More code here......................
The notifications are received on background but I can't invoke any javascript methods since gwebView points nothing.
My approach is to show a generic notification on statusbar whenever gwebView has a null pointer but I just don't know how to get the application or cordova context in order to use this function.
Any help would be appreciated, thanks

I found in google forums that this is a bug of the plugin so I decided to use Pushwhoosh notification service.

Related

Android New relic track non Network error

are there any way to track handled errors on New Relic?
Documentation says that we can track with
NewRelic.noticeNetworkFailure(...)
however I've tried to track errors which aren't from any network call and with a fake URL but I got this:
'java.lang.String com.newrelic.agent.android.api.common.TransactionData.getUrl()' on a null object reference
Other platforms like JAVA have this
NewRelic.noticeError(e);
but the android platform does not have a method to notice a simple error.
do you know how we can send handled errors?
At the end, there is way to track an error however it won't appear in you crashList.
The notice methods that New Relic has allow you to notice error. With a method like the below one you can send a notice that will appear in your Network --> error page
public static void reportLoggedException(String message, Throwable tr) {
long time = new Date().getTime();
try {
if (message.isEmpty()) {
message = "none";
}
NewRelic.noticeNetworkFailure("http://" + URLEncoder.encode(message, "utf-8")+".com", "GET", time, time, new Exception(tr));
} catch (Exception e) {
e.printStackTrace();
}
}

Sony QX100 return 403 error for supported methods

I am trying to set the Exposure mode and Focus mode for my QX100 device. Each time I make the API call I get a 403 error. However, these two methods setExposureMode and setFocusMode are supported by the QX100 as it clearly states in the API docs. In addition, I can set the focus mode through Playmemories. This same problem also occurs with setBeepMode, which is also supported. Any ideas about why this could be occurring?
There are some supported methods that are working, such as actTakePicture and setPostviewImageSize
An example call:
public JSONObject setFocusMode() throws IOException {
String service = "camera";
try {
JSONObject requestJson =
new JSONObject().put("method", "setFocusMode").put("params", new JSONArray().put("MF")) //
.put("id", id()).put("version", "1.0");
String url = findActionListUrl(service) + "/" + service;
log("Request: " + requestJson.toString());
JSONObject responseJson = SimpleHttpClient.httpPost(url, requestJson, null);
log("Response: " + responseJson.toString());
return responseJson;
} catch (JSONException e) {
throw new IOException(e);
}
}
Is your QX100 updated to the latest firmware? On old one, most of APIs are restricted.
Or they may be temporary disabled. You can use getAvailableApiList to know that.

Second HttpURLConnection is failing

I have a ListView that onLongClick it calls a method that is supposed to go out to a website, pull a jsonArray from it and then return information that is pulled from the array. However, when it calls the HttpURLConnection.connect() method it fails and goes to the catch block. When I use the getMessage() message on the exception it only returns Null. This is the second time in this program that I've connected to a URL in this same way and it works the first time perfectly. What could be causing this issue?
Here is the code for when the method is called:
list.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
public boolean onItemLongClick(AdapterView<?> a, View v, int pos, long id) {
String trainNum = list.getItemAtPosition(pos).toString();
String info = "hello";
try {
info = getCurrentTrainInfo(trainNum);
}catch(Exception e){
info = e.getMessage();
if(info == null)
info = "info is null";
tv.setText(info);
}
Toast.makeText(getApplicationContext(), info, Toast.LENGTH_LONG).show();
return true;
}
}
);
And here is the method getCurrentTrainInfo that is called in the try block above:
public String getCurrentTrainInfo(String num) throws IOException{
String sURL = "http://www3.septa.org/hackathon/RRSchedules/" + num;
URL url = new URL(sURL);
HttpURLConnection request2 = (HttpURLConnection) url.openConnection();
request2.connect();
JsonParser jp = new JsonParser();
JsonElement root = jp.parse(new InputStreamReader((InputStream) request.getContent()));
JsonArray rootArr = root.getAsJsonArray();
int i = 0;
String acTime = "";
String station = rootArr.get(i).getAsJsonObject().get("station").getAsString();
String schTime = rootArr.get(i).getAsJsonObject().get("sched_tm").getAsString();
String esTime = rootArr.get(i).getAsJsonObject().get("est_tm").getAsString();
tv.setText(station);
String info = "Current Station: " + station + "\nScheduled leave time: " + schTime + "\nEstimated leave time: " + esTime;*/
return info;
}
Is there anything I can do to fix this problem?
I see your request is being made ​​in the UI thread, you mentioned that in another moment used this same way and it worked, I believe this may have happened when you ran your application on a device/emulator with a version of Android prior to 3.0.
Within an Android application you should avoid performing long
running operations on the user interface thread. This includes file
and network access. StrictMode allows to setup policies in your
application to avoid doing incorrect things. As of Android 3.0
(Honeycomb) StrictMode is configured to crash with a
NetworkOnMainThreadException exception, if network is accessed in
the user interface thread.
You can create a AsyncTasks class and move the call request to it.

Get crash report in google analytics

I want to receive notification regarding crash report due to uncaught exception in my google analytics for my android app. I followed the steps given in https://developers.google.com/analytics/devguides/collection/android/v4/exceptions#parsing
but still I dont receive any crash report. I had a runtime exception when my app runs. I added the code for ga_reportUncaughtException as true:
true
in my analytics.xml. Is there anything else I need to add in order to get hit in google analytics account. Please help!
There is an open issue in Analytics. I'm experiencing the same behavior but on real devices from API 10 to 19.
https://code.google.com/p/analytics-issues/issues/detail?id=443
EDIT1: Removed question, just to answer the question described.
EDIT2: I tried to capture and send the exceptions using the Analytics ExceptionBuilder, but it didn't work.
It looks like the report is sent (at least LogCat is showing that the crash is reported), but it is not processed by Analytics.
While Google replies to the issue, I'm using this workaround. I guess it is not the best solution and the code can be improved, but it works for me:
I created a custom dimension in Analytics following this steps https://support.google.com/analytics/answer/2709829?hl=en
In my App, I created a custom exception handler, using the Analytics ExceptionReporter class. When an exception is caught, I get the stack trace and truncate it to 150 Bytes (Actually I'm getting only the first line of the stack and truncate it to 150 chars. I'm assuming that 1Char = 1 Byte). I have to truncate it, because it is the Max Lenght allowed by Analytics when sending custom dimensions values.
The stack trace is stored in a Shared Preference instead of being sent. I tried to send it directly, but it does not work once the App has crashed.
package com.company.package;
import java.lang.Thread.UncaughtExceptionHandler;
import android.content.Context;
import com.google.android.gms.analytics.ExceptionParser;
import com.google.android.gms.analytics.ExceptionReporter;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
public class GoogleAnalyticsTracker {
private static Tracker mTracker;
private static GoogleAnalytics mGa;
private Context mContext;
public GoogleAnalyticsTracker(Context context, int resource) {
mContext = context;
mGa = GoogleAnalytics.getInstance(context);
mTracker = getTracker(resource);
Thread.setDefaultUncaughtExceptionHandler(new AnalyticsExceptionReporter(mTracker,
Thread.getDefaultUncaughtExceptionHandler(), context));
}
synchronized Tracker getTracker(int xmlResource) {
return mGa.newTracker(xmlResource);
}
public void sendScreenLabel(String screenLabel) {
mTracker.setScreenName(screenLabel);
mTracker.send(new HitBuilders.AppViewBuilder().build());
}
public void sendCustomDimension(int index, String value) {
mTracker.send(new HitBuilders.AppViewBuilder().setCustomDimension(index, value).build());
}
private class AnalyticsExceptionReporter extends ExceptionReporter {
public AnalyticsExceptionReporter(Tracker tracker, UncaughtExceptionHandler originalHandler, Context context) {
super(tracker, originalHandler, context);
setExceptionParser(new AnalyticsExceptionParser());
}
#Override
public void uncaughtException(Thread t, Throwable e) {
String exceptionDescription = getExceptionParser().getDescription(t.getName(), e);
//Add code to store the exception stack trace in shared preferences
super.uncaughtException(t, e);
}
}
private class AnalyticsExceptionParser implements ExceptionParser {
#Override
public String getDescription(String arg0, Throwable arg1) {
StringBuilder exceptionFirsLine = new StringBuilder();
for (StackTraceElement element : arg1.getStackTrace()) {
exceptionFirsLine.append(element.toString());
break;
}
//150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8)
String exceptionDescription = exceptionFirsLine.toString();
if(exceptionDescription.length() > 150)
exceptionDescription = exceptionDescription.substring(0, 149);
return exceptionDescription;
}
}
}
In the MainActivity when OnStart(), I check if there is any stored stack trace in the shared preferences. If so, I send the custom dimension and clear the shared preference.
#Override
protected void onStart() {
super.onStart();
String exception = getExceptionFromSharedPreferences(this);
if(exception != null && !exception.isEmpty()) {
MainApplication.googleAnalyticsTracker.sendCustomDimension(1, exception);
}
clearExceptionFromSharedPreferences(this);
}
Finally I created a custom report in Analytics
EDIT 3:
I realized that I was sending only the fileName and lineNumber, but not the ExceptionName and the origin of the Exception in my package. I have improved the answer by adding code to also send that info.
private class AnalyticsExceptionParser implements ExceptionParser {
#Override
public String getDescription(String arg0, Throwable arg1) {
String exceptionDescription = getExceptionInfo(arg1, "", true) + getCauseExceptionInfo(arg1.getCause());
//150 Bytes is the maximum allowed by Analytics for custom dimensions values. Assumed that 1 Byte = 1 Character (UTF-8)
if(exceptionDescription.length() > 150)
exceptionDescription = exceptionDescription.substring(0, 150);
return exceptionDescription;
}
}
//#endregion
//#region PRIVATE METHODS
private String getCauseExceptionInfo(Throwable t) {
String causeDescription = "";
while(t != null && causeDescription.isEmpty()) {
causeDescription = getExceptionInfo(t, "com.myPackageName", false);
t = t.getCause();
}
return causeDescription;
}
private String getExceptionInfo(Throwable t, String packageName, boolean includeExceptionName) {
String exceptionName = "";
String fileName = "";
String lineNumber = "";
for (StackTraceElement element : t.getStackTrace()) {
String className = element.getClassName().toString().toLowerCase();
if(packageName.isEmpty() || (!packageName.isEmpty() && className.contains(packageName))){
exceptionName = includeExceptionName ? t.toString() : "";
fileName = element.getFileName();
lineNumber = String.valueOf(element.getLineNumber());
return exceptionName + "#" + fileName + ":" + lineNumber;
}
}
return "";
}
From my experience you need to understand two things about crashes and exceptions in Google Analytics:
1) Only basic information is stored - Google Analytics will only save the name of the exception and the location (Code file and line number) where the exception was thrown. No information beyond that will be accessible to you on GA. This is definitely not ideal and if you wish to track the actual content of your exceptions (mainly the call stack), use Google Play or implement your own solution.
2) Exceptions are not real-time. Exception information is collected and updated maybe once a day, so if you're experimenting with exceptions and you don't see them immediately, just give it time.

How do I use RunOnUiThread to update some TextViews on a screen

Alrighty, so I understand that this general question has been asked numerous times here, but I have yet to find an answer that makes sense to me. Almost every answer I've seen just says some blurb like, "hey, just throw this in your method and you're good", but I'm not seeing full examples, and what I've tried is not working either.
Here's the error I receive:
[mono] android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
So, simply put, I have an activity that grabs some information from a web service and then throws the web service results into a couple of TextViews. Could someone please help me figure out where and how I need to use the RunOnUiThread()? Here's the code:
using Android.App;
using Android.OS;
using System;
using System.Web;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using Android.Widget;
namespace DispatchIntranet
{
[Activity (Label = "#string/Summary")]
public class SummaryActivity : Activity
{
private static readonly Log LOG = new Log(typeof(SummaryActivity));
private TextView summaryTotalRegularLabel;
private TextView summaryTotalRollover;
private TextView summaryScheduledLabel;
private TextView summaryRemainingRegular;
private string url;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// SET THE LAYOUT TO BE THE SUMMARY LAYOUT
SetContentView(Resource.Layout.Summary);
// INITIALIZE CLASS MEMBERS
init();
if (LOG.isInfoEnabled())
{
LOG.info("Making call to rest endpoint . . .");
if (LOG.isDebugEnabled())
{
LOG.debug("url: " + this.url);
}
}
try
{
// BUILD REQUEST FROM URL
HttpWebRequest httpReq = (HttpWebRequest)HttpWebRequest.Create(new Uri(this.url));
// SET METHOD TO 'GET'
httpReq.Method = GetString(Resource.String.web_service_method_get);
// ASK FOR JSON RESPONSE
httpReq.Accept = GetString(Resource.String.web_service_method_accept);
// INVOKE ASYNCHRONOUS WEB SERVICE
httpReq.BeginGetResponse((ar) => {
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse (ar))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
// PUT RESPONSE INTO STRING
string content = reader.ReadToEnd();
// CONVERT STRING TO DYNAMIC JSON OBJECT
var json = JsonConvert.DeserializeObject<dynamic>(content);
if (LOG.isDebugEnabled())
{
LOG.debug("content: " + content);
LOG.debug("json: " + json);
LOG.debug("TOTAL_REGULAR_PTO_HOURS: " + json.d[0].TOTAL_REGULAR_PTO_HOURS);
}
// ** THIS IS WHAT WILL NOT WORK **
this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
}
}
}, httpReq);
}
catch (Exception e)
{
LOG.error("An exception occurred while attempting to call REST web service!", e);
}
}
private void init()
{
// GET GUID FROM PREVIOUS INTENT AND DETERMINE CURRENT YEAR
string guid = Intent.GetStringExtra("guid");
int year = DateTime.Now.Year;
// BUILD URL
this.url = GetString(Resource.String.web_service_url)
+ GetString(Resource.String.ws_get_pto_summary)
+ "?" + "guid='" + HttpUtility.UrlEncode(guid) + "'"
+ "&" + "year=" + HttpUtility.UrlEncode(year.ToString());
// GET THE SUMMARY LABELS
this.summaryTotalRegularLabel = FindViewById<TextView>(Resource.Id.SummaryTotalRegular);
this.summaryTotalRollover = FindViewById<TextView>(Resource.Id.summaryTotalRollover);
this.summaryScheduledLabel = FindViewById<TextView>(Resource.Id.summaryScheduledLabel);
this.summaryRemainingRegular = FindViewById<TextView>(Resource.Id.SummaryRemainingRegular);
}
}
}
When you make a web service call, HttpWebRequest creates a new thread to run the operation on. This is done to keep your user interface from locking up or skip frames. Once your web service call is complete, you need to go back to the UI Thread to update the UI components that live on that thread. You can do that a couple of different ways.
First, you can wrap your code in an anonymous function call like so:
RunOnUiThread(()=>{
this.summaryTotalRegularLabel.Text = json.d[0].TOTAL_REGULAR_PTO_HOURS;
this.summaryTotalRollover.Text = json.d[0].TOTAL_ROLLOVER_PTO_HOURS;
this.summaryScheduledLabel.Text = json.d[0].TOTAL_USED_PTO_HOURS;
this.summaryRemainingRegular.Text = json.d[0].TOTAL_REMAINING_PTO_HOURS;
});
Or you can call a function via RunOnUiThread (jsonPayload is a field on the class):
jsonPayload = json;
RunOnUiThread(UpdateTextViews);
...
void UpdateTextViews()
{
this.summaryTotalRegularLabel.Text = jsonPayload.d[0].TOTAL_REGULAR_PTO_HOURS;
this.summaryTotalRollover.Text = jsonPayload.d[0].TOTAL_ROLLOVER_PTO_HOURS;
this.summaryScheduledLabel.Text = jsonPayload.d[0].TOTAL_USED_PTO_HOURS;
this.summaryRemainingRegular.Text = jsonPayload.d[0].TOTAL_REMAINING_PTO_HOURS;
}

Categories

Resources