Fixed problem with Android 8 permissions. Needed to implement a new unhandled Exception Handler because mine kept giving Permission Denied errors.

This commit is contained in:
Graham Jones
2019-01-26 23:53:27 +00:00
parent 76df111876
commit b217259ca5
13 changed files with 770 additions and 28 deletions

View File

@@ -41,6 +41,7 @@ dependencies {
implementation 'com.google.android.gms:play-services:10.0.1'
implementation 'com.github.wendykierp:JTransforms:3.0'
implementation 'com.google.android.gms:play-services-location:10.0.0'
//implementation 'com.github.RohitSurwase.UCE-Handler:uce_handler:1.3'
}

View File

@@ -44,6 +44,9 @@
<activity
android:name=".PrefActivity"
android:label="OpenSeizureDetector Preferences"></activity>
<activity
android:name="com.rohitss.uceh.UCEDefaultActivity"
android:process=":error_activity"></activity>
<service
android:name=".SdServer"

View File

@@ -0,0 +1,332 @@
/*
*
* * Copyright © 2018 Rohit Sahebrao Surwase.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package com.rohitss.uceh;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import uk.org.openseizuredetector.R;
/**
* <b></b>
* <p>This class is used to </p>
* Created by Rohit.
*/
public final class UCEDefaultActivity extends Activity {
private File txtFile;
private String strCurrentErrorLog;
private String TAG = "UCEDefaultActivity";
@SuppressLint("PrivateResource")
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(android.R.style.Theme_Holo_Light_DarkActionBar);
super.onCreate(savedInstanceState);
Log.i(TAG,"onCreate()");
setContentView(R.layout.default_error_activity);
findViewById(R.id.button_close_app).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
UCEHandler.closeApplication(UCEDefaultActivity.this);
}
});
findViewById(R.id.button_copy_error_log).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
copyErrorToClipboard();
}
});
findViewById(R.id.button_share_error_log).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareErrorLog();
}
});
findViewById(R.id.button_save_error_log).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveErrorLogToFile(true);
}
});
findViewById(R.id.button_email_error_log).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
emailErrorLog();
}
});
findViewById(R.id.button_view_error_log).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AlertDialog dialog = new AlertDialog.Builder(UCEDefaultActivity.this)
.setTitle("Error Log")
.setMessage(getAllErrorDetailsFromIntent(UCEDefaultActivity.this, getIntent()))
.setPositiveButton("Copy Log & Close",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
copyErrorToClipboard();
dialog.dismiss();
}
})
.setNeutralButton("Close",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
TextView textView = dialog.findViewById(android.R.id.message);
if (textView != null) {
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
}
}
});
}
public String getApplicationName(Context context) {
ApplicationInfo applicationInfo = context.getApplicationInfo();
int stringId = applicationInfo.labelRes;
return stringId == 0 ? applicationInfo.nonLocalizedLabel.toString() : context.getString(stringId);
}
private String getVersionName(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionName;
} catch (Exception e) {
return "Unknown";
}
}
private String getActivityLogFromIntent(Intent intent) {
return intent.getStringExtra(UCEHandler.EXTRA_ACTIVITY_LOG);
}
private String getStackTraceFromIntent(Intent intent) {
return intent.getStringExtra(UCEHandler.EXTRA_STACK_TRACE);
}
private String getEmailAddressesFromIntent(Intent intent) {
Log.d(TAG,"getEmailFromIntent - "+intent.getStringExtra(UCEHandler.EXTRA_EMAIL_ADDRESSES)+".");
return intent.getStringExtra(UCEHandler.EXTRA_EMAIL_ADDRESSES);
}
private void emailErrorLog() {
saveErrorLogToFile(false);
String errorLog = getAllErrorDetailsFromIntent(UCEDefaultActivity.this, getIntent());
Log.d(TAG,"emailErrorLog() - addresses = "+UCEHandler.COMMA_SEPARATED_EMAIL_ADDRESSES+".");
//String[] emailAddressArray = UCEHandler.COMMA_SEPARATED_EMAIL_ADDRESSES.trim().split("\\s*,\\s*");
String emailStr = getEmailAddressesFromIntent(getIntent());
Log.d(TAG,"emailErrorLog() - EmailStr = "+emailStr);
String[] emailAddressArray = emailStr.split("\\s*,\\s*");
//String[] emailAddressArray = {"crashreports@openseizuredetector.org.uk"};
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
emailIntent.setType("plain/text");
emailIntent.putExtra(Intent.EXTRA_EMAIL, emailAddressArray);
emailIntent.putExtra(Intent.EXTRA_SUBJECT, getApplicationName(UCEDefaultActivity.this) + " Application Crash Error Log");
emailIntent.putExtra(Intent.EXTRA_TEXT, getString(R.string.email_welcome_note) + errorLog);
//if (txtFile.exists()) {
// Uri filePath = Uri.fromFile(txtFile);
// emailIntent.putExtra(Intent.EXTRA_STREAM, filePath);
//}
startActivity(Intent.createChooser(emailIntent, "Email Error Log"));
}
private void saveErrorLogToFile(boolean isShowToast) {
Boolean isSDPresent = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
if (isSDPresent && isExternalStorageWritable()) {
Date currentDate = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
String strCurrentDate = dateFormat.format(currentDate);
strCurrentDate = strCurrentDate.replace(" ", "_");
String errorLogFileName = getApplicationName(UCEDefaultActivity.this) + "_Error-Log_" + strCurrentDate;
String errorLog = getAllErrorDetailsFromIntent(UCEDefaultActivity.this, getIntent());
String fullPath = Environment.getExternalStorageDirectory() + "/AppErrorLogs_UCEH/";
FileOutputStream outputStream;
try {
File file = new File(fullPath);
file.mkdir();
txtFile = new File(fullPath + errorLogFileName + ".txt");
txtFile.createNewFile();
outputStream = new FileOutputStream(txtFile);
outputStream.write(errorLog.getBytes());
outputStream.close();
if (txtFile.exists() && isShowToast) {
Toast.makeText(this, "File Saved Successfully", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
Log.e("REQUIRED", "This app does not have write storage permission to save log file.");
if (isShowToast) {
Toast.makeText(this, "Storage Permission Not Found", Toast.LENGTH_SHORT).show();
}
e.printStackTrace();
}
}
}
private void shareErrorLog() {
String errorLog = getAllErrorDetailsFromIntent(UCEDefaultActivity.this, getIntent());
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("text/plain");
share.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
share.putExtra(Intent.EXTRA_SUBJECT, "Application Crash Error Log");
share.putExtra(Intent.EXTRA_TEXT, errorLog);
startActivity(Intent.createChooser(share, "Share Error Log"));
}
private void copyErrorToClipboard() {
String errorInformation = getAllErrorDetailsFromIntent(UCEDefaultActivity.this, getIntent());
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
if (clipboard != null) {
ClipData clip = ClipData.newPlainText("View Error Log", errorInformation);
clipboard.setPrimaryClip(clip);
Toast.makeText(UCEDefaultActivity.this, "Error Log Copied", Toast.LENGTH_SHORT).show();
}
}
private String getAllErrorDetailsFromIntent(Context context, Intent intent) {
if (TextUtils.isEmpty(strCurrentErrorLog)) {
String LINE_SEPARATOR = "\n";
StringBuilder errorReport = new StringBuilder();
errorReport.append("***** UCE HANDLER Library ");
errorReport.append("\n***** by Rohit Surwase \n");
errorReport.append("\n***** DEVICE INFO \n");
errorReport.append("Brand: ");
errorReport.append(Build.BRAND);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Device: ");
errorReport.append(Build.DEVICE);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Model: ");
errorReport.append(Build.MODEL);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Manufacturer: ");
errorReport.append(Build.MANUFACTURER);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Product: ");
errorReport.append(Build.PRODUCT);
errorReport.append(LINE_SEPARATOR);
errorReport.append("SDK: ");
errorReport.append(Build.VERSION.SDK);
errorReport.append(LINE_SEPARATOR);
errorReport.append("Release: ");
errorReport.append(Build.VERSION.RELEASE);
errorReport.append(LINE_SEPARATOR);
errorReport.append("\n***** APP INFO \n");
String versionName = getVersionName(context);
errorReport.append("Version: ");
errorReport.append(versionName);
errorReport.append(LINE_SEPARATOR);
Date currentDate = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
String firstInstallTime = getFirstInstallTimeAsString(context, dateFormat);
if (!TextUtils.isEmpty(firstInstallTime)) {
errorReport.append("Installed On: ");
errorReport.append(firstInstallTime);
errorReport.append(LINE_SEPARATOR);
}
String lastUpdateTime = getLastUpdateTimeAsString(context, dateFormat);
if (!TextUtils.isEmpty(lastUpdateTime)) {
errorReport.append("Updated On: ");
errorReport.append(lastUpdateTime);
errorReport.append(LINE_SEPARATOR);
}
errorReport.append("Current Date: ");
errorReport.append(dateFormat.format(currentDate));
errorReport.append(LINE_SEPARATOR);
errorReport.append("\n***** ERROR LOG \n");
errorReport.append(getStackTraceFromIntent(intent));
errorReport.append(LINE_SEPARATOR);
String activityLog = getActivityLogFromIntent(intent);
errorReport.append(LINE_SEPARATOR);
if (activityLog != null) {
errorReport.append("\n***** USER ACTIVITIES \n");
errorReport.append("User Activities: ");
errorReport.append(activityLog);
errorReport.append(LINE_SEPARATOR);
}
errorReport.append("\n***** END OF LOG *****\n");
strCurrentErrorLog = errorReport.toString();
return strCurrentErrorLog;
} else {
return strCurrentErrorLog;
}
}
private String getFirstInstallTimeAsString(Context context, DateFormat dateFormat) {
long firstInstallTime;
try {
firstInstallTime = context
.getPackageManager()
.getPackageInfo(context.getPackageName(), 0)
.firstInstallTime;
return dateFormat.format(new Date(firstInstallTime));
} catch (PackageManager.NameNotFoundException e) {
return "";
}
}
private String getLastUpdateTimeAsString(Context context, DateFormat dateFormat) {
long lastUpdateTime;
try {
lastUpdateTime = context
.getPackageManager()
.getPackageInfo(context.getPackageName(), 0)
.lastUpdateTime;
return dateFormat.format(new Date(lastUpdateTime));
} catch (PackageManager.NameNotFoundException e) {
return "";
}
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
}

View File

@@ -0,0 +1,271 @@
/*
*
* * Copyright © 2018 Rohit Sahebrao Surwase.
* *
* * Licensed under the Apache License, Version 2.0 (the "License");
* * you may not use this file except in compliance with the License.
* * You may obtain a copy of the License at
* *
* * http://www.apache.org/licenses/LICENSE-2.0
* *
* * Unless required by applicable law or agreed to in writing, software
* * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* * See the License for the specific language governing permissions and
* * limitations under the License.
*
*/
package com.rohitss.uceh;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayDeque;
import java.util.Date;
import java.util.Deque;
import java.util.Locale;
/**
* <b></b>
* <p>This class is used to </p>
* Created by Rohit.
*/
public final class UCEHandler {
static final String EXTRA_STACK_TRACE = "EXTRA_STACK_TRACE";
static final String EXTRA_ACTIVITY_LOG = "EXTRA_ACTIVITY_LOG";
static final String EXTRA_EMAIL_ADDRESSES = "EXTRA_EMAIL_ADDRESSES";
private final static String TAG = "UCEHandler";
private static final String UCE_HANDLER_PACKAGE_NAME = "com.rohitss.uceh";
private static final String DEFAULT_HANDLER_PACKAGE_NAME = "com.android.internal.os";
private static final int MAX_STACK_TRACE_SIZE = 131071; //128 KB - 1
private static final int MAX_ACTIVITIES_IN_LOG = 50;
private static final String SHARED_PREFERENCES_FILE = "uceh_preferences";
private static final String SHARED_PREFERENCES_FIELD_TIMESTAMP = "last_crash_timestamp";
private static final Deque<String> activityLog = new ArrayDeque<>(MAX_ACTIVITIES_IN_LOG);
static String COMMA_SEPARATED_EMAIL_ADDRESSES;
@SuppressLint("StaticFieldLeak")
private static Application application;
private static boolean isInBackground = true;
private static boolean isBackgroundMode;
private static boolean isUCEHEnabled;
private static boolean isTrackActivitiesEnabled;
private static WeakReference<Activity> lastActivityCreated = new WeakReference<>(null);
UCEHandler(Builder builder) {
isUCEHEnabled = builder.isUCEHEnabled;
isTrackActivitiesEnabled = builder.isTrackActivitiesEnabled;
isBackgroundMode = builder.isBackgroundModeEnabled;
COMMA_SEPARATED_EMAIL_ADDRESSES = builder.commaSeparatedEmailAddresses;
Log.d(TAG,"UCEHandler() - Email Addresses = "+COMMA_SEPARATED_EMAIL_ADDRESSES+".");
Log.d(TAG,"UCEHandler() - UCEHandler.Email Addresses = "+UCEHandler.COMMA_SEPARATED_EMAIL_ADDRESSES+".");
setUCEHandler(builder.context);
}
private static void setUCEHandler(final Context context) {
Log.i(TAG,"setUCEHandler() - email addresses = "+UCEHandler.COMMA_SEPARATED_EMAIL_ADDRESSES+".");
try {
if (context != null) {
final Thread.UncaughtExceptionHandler oldHandler = Thread.getDefaultUncaughtExceptionHandler();
if (oldHandler != null && oldHandler.getClass().getName().startsWith(UCE_HANDLER_PACKAGE_NAME)) {
Log.e(TAG, "UCEHandler was already installed, doing nothing!");
} else {
if (oldHandler != null && !oldHandler.getClass().getName().startsWith(DEFAULT_HANDLER_PACKAGE_NAME)) {
Log.e(TAG, "You already have an UncaughtExceptionHandler. If you use a custom UncaughtExceptionHandler, it should be initialized after UCEHandler! Installing anyway, but your original handler will not be called.");
}
application = (Application) context.getApplicationContext();
//Setup UCE Handler.
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, final Throwable throwable) {
if (isUCEHEnabled) {
Log.e(TAG, "App crashed, executing UCEHandler's UncaughtExceptionHandler", throwable);
if (hasCrashedInTheLastSeconds(application)) {
Log.e(TAG, "App already crashed recently, not starting custom error activity because we could enter a restart loop. Are you sure that your app does not crash directly on init?", throwable);
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
} else {
setLastCrashTimestamp(application, new Date().getTime());
if (!isInBackground || isBackgroundMode) {
Log.d(TAG,"Preparing Intent");
final Intent intent = new Intent(application, UCEDefaultActivity.class);
intent.putExtra(EXTRA_EMAIL_ADDRESSES, COMMA_SEPARATED_EMAIL_ADDRESSES);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
String stackTraceString = sw.toString();
if (stackTraceString.length() > MAX_STACK_TRACE_SIZE) {
String disclaimer = " [stack trace too large]";
stackTraceString = stackTraceString.substring(0, MAX_STACK_TRACE_SIZE - disclaimer.length()) + disclaimer;
}
intent.putExtra(EXTRA_STACK_TRACE, stackTraceString);
if (isTrackActivitiesEnabled) {
StringBuilder activityLogStringBuilder = new StringBuilder();
while (!activityLog.isEmpty()) {
activityLogStringBuilder.append(activityLog.poll());
}
intent.putExtra(EXTRA_ACTIVITY_LOG, activityLogStringBuilder.toString());
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Log.d(TAG,"calling startActivity()");
application.startActivity(intent);
} else {
Log.d(TAG,"using oldHandler");
if (oldHandler != null) {
oldHandler.uncaughtException(thread, throwable);
return;
}
//If it is null (should not be), we let it continue and kill the process or it will be stuck
}
}
final Activity lastActivity = lastActivityCreated.get();
if (lastActivity != null) {
lastActivity.finish();
lastActivityCreated.clear();
}
killCurrentProcess();
} else if (oldHandler != null) {
//Pass control to old uncaught exception handler
oldHandler.uncaughtException(thread, throwable);
}
}
});
application.registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
int currentlyStartedActivities = 0;
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (activity.getClass() != UCEDefaultActivity.class) {
lastActivityCreated = new WeakReference<>(activity);
}
if (isTrackActivitiesEnabled) {
activityLog.add(dateFormat.format(new Date()) + ": " + activity.getClass().getSimpleName() + " created\n");
}
}
@Override
public void onActivityStarted(Activity activity) {
currentlyStartedActivities++;
isInBackground = (currentlyStartedActivities == 0);
}
@Override
public void onActivityResumed(Activity activity) {
if (isTrackActivitiesEnabled) {
activityLog.add(dateFormat.format(new Date()) + ": " + activity.getClass().getSimpleName() + " resumed\n");
}
}
@Override
public void onActivityPaused(Activity activity) {
if (isTrackActivitiesEnabled) {
activityLog.add(dateFormat.format(new Date()) + ": " + activity.getClass().getSimpleName() + " paused\n");
}
}
@Override
public void onActivityStopped(Activity activity) {
currentlyStartedActivities--;
isInBackground = (currentlyStartedActivities == 0);
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (isTrackActivitiesEnabled) {
activityLog.add(dateFormat.format(new Date()) + ": " + activity.getClass().getSimpleName() + " destroyed\n");
}
}
});
}
Log.i(TAG, "UCEHandler has been installed.");
} else {
Log.e(TAG, "Context can not be null");
}
} catch (Throwable throwable) {
Log.e(TAG, "UCEHandler can not be initialized. Help making it better by reporting this as a bug.", throwable);
}
}
/**
* INTERNAL method that tells if the app has crashed in the last seconds.
* This is used to avoid restart loops.
*
* @return true if the app has crashed in the last seconds, false otherwise.
*/
private static boolean hasCrashedInTheLastSeconds(Context context) {
long lastTimestamp = getLastCrashTimestamp(context);
long currentTimestamp = new Date().getTime();
return (lastTimestamp <= currentTimestamp && currentTimestamp - lastTimestamp < 3000);
}
@SuppressLint("ApplySharedPref")
private static void setLastCrashTimestamp(Context context, long timestamp) {
context.getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE).edit().putLong(SHARED_PREFERENCES_FIELD_TIMESTAMP, timestamp).commit();
}
private static void killCurrentProcess() {
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
private static long getLastCrashTimestamp(Context context) {
return context.getSharedPreferences(SHARED_PREFERENCES_FILE, Context.MODE_PRIVATE).getLong(SHARED_PREFERENCES_FIELD_TIMESTAMP, -1);
}
static void closeApplication(Activity activity) {
activity.finish();
killCurrentProcess();
}
public static class Builder {
private Context context;
private boolean isUCEHEnabled = true;
private String commaSeparatedEmailAddresses;
private boolean isTrackActivitiesEnabled = false;
private boolean isBackgroundModeEnabled = true;
public Builder(Context context) {
this.context = context;
}
public Builder setUCEHEnabled(boolean isUCEHEnabled) {
this.isUCEHEnabled = isUCEHEnabled;
return this;
}
public Builder setTrackActivitiesEnabled(boolean isTrackActivitiesEnabled) {
this.isTrackActivitiesEnabled = isTrackActivitiesEnabled;
return this;
}
public Builder setBackgroundModeEnabled(boolean isBackgroundModeEnabled) {
this.isBackgroundModeEnabled = isBackgroundModeEnabled;
return this;
}
public Builder addCommaSeparatedEmailAddresses(String commaSeparatedEmailAddresses) {
this.commaSeparatedEmailAddresses = (commaSeparatedEmailAddresses != null) ? commaSeparatedEmailAddresses : "";
return this;
}
public UCEHandler build() {
return new UCEHandler(this);
}
}
}

View File

@@ -61,6 +61,7 @@ import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.utils.ValueFormatter;
import com.rohitss.uceh.UCEHandler;
public class MainActivity extends AppCompatActivity {
static final String TAG = "MainActivity";
@@ -89,7 +90,11 @@ public class MainActivity extends AppCompatActivity {
Log.i(TAG,"onCreate()");
// Set our custom uncaught exception handler to report issues.
Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(MainActivity.this));
//Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(MainActivity.this));
new UCEHandler.Builder(this)
.addCommaSeparatedEmailAddresses("crashreports@openseizuredetector.org.uk,")
.build();
//int i = 5/0; // Force exception to test handler.
mUtil = new OsdUtil(this,serverStatusHandler);
mConnection = new SdServiceConnection(this);

View File

@@ -163,8 +163,8 @@ public class OsdUncaughtExceptionHandler implements Thread.UncaughtExceptionHand
"You can review the information being sent in the next screen:"+
"\n"+errorContent.toString());
Dialog dialog = builder.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
//dialog.show();
//dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
Looper.loop();
}
}.start();

View File

@@ -91,6 +91,9 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
private final String[] REQUIRED_PERMISSIONS = {
Manifest.permission.SEND_SMS,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
//Manifest.permission.SYSTEM_ALERT_WINDOW,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WAKE_LOCK,
};
/**
@@ -342,24 +345,30 @@ public class OsdUtil implements ActivityCompat.OnRequestPermissionsResultCallbac
fname = fname + "_" + dateStr + ".txt";
// Open output directory on SD Card.
if (isExternalStorageWritable()) {
try {
FileWriter of = new FileWriter(getDataStorageDir().toString()
+ "/" + fname, true);
if (msgStr != null) {
String dateTimeStr = tnow.format("%Y-%m-%d %H:%M:%S");
Log.v(TAG, "writing msgStr");
of.append(dateTimeStr+", "
+tnow.toMillis(true)+", "
+msgStr+"<br/>\n");
}
of.close();
} catch (Exception ex) {
Log.e(TAG, "writeToLogFile - error " + ex.toString());
showToast("ERROR Writing to Log File");
}
if (ContextCompat.checkSelfPermission(mContext,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
Log.e(TAG,"ERROR: We do not have permission to write to external storage");
} else {
Log.e(TAG, "ERROR - Can not Write to External Folder");
if (isExternalStorageWritable()) {
try {
FileWriter of = new FileWriter(getDataStorageDir().toString()
+ "/" + fname, true);
if (msgStr != null) {
String dateTimeStr = tnow.format("%Y-%m-%d %H:%M:%S");
Log.v(TAG, "writing msgStr");
of.append(dateTimeStr + ", "
+ tnow.toMillis(true) + ", "
+ msgStr + "<br/>\n");
}
of.close();
} catch (Exception ex) {
Log.e(TAG, "writeToLogFile - error " + ex.toString());
showToast("ERROR Writing to Log File");
}
} else {
Log.e(TAG, "ERROR - Can not Write to External Folder");
}
}
}

View File

@@ -40,6 +40,7 @@ import com.getpebble.android.kit.PebbleKit;
import com.getpebble.android.kit.util.PebbleDictionary;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jtransforms.fft.DoubleFFT_1D;
@@ -373,7 +374,12 @@ public class SdDataSourceGarmin extends SdDataSource {
Log.v(TAG,"updateFromJSON - dataType="+dataTypeStr);
if (dataTypeStr.equals("raw")) {
Log.v(TAG,"updateFromJSON - processing raw data");
mSdData.mHR = dataObject.getDouble("HR");
try {
mSdData.mHR = dataObject.getDouble("HR");
} catch (JSONException e) {
// if we get 'null' HR (For example if the heart rate is not working)
mSdData.mHR = -1;
}
JSONArray accelVals = dataObject.getJSONArray("data");
Log.v(TAG, "Received " + accelVals.length() + " acceleration values");
int i;

View File

@@ -68,6 +68,8 @@ import java.util.*;
import android.text.format.Time;
import com.rohitss.uceh.UCEHandler;
/**
* Based on example at:
@@ -169,15 +171,18 @@ public class SdServer extends Service implements SdDataReceiver, SdLocationRecei
mUtil.writeToSysLogFile("SdServer.onCreate()");
// Set our custom uncaught exception handler to report issues.
Thread.setDefaultUncaughtExceptionHandler(
new OsdUncaughtExceptionHandler(SdServer.this));
//Thread.setDefaultUncaughtExceptionHandler(
// new OsdUncaughtExceptionHandler(SdServer.this));
new UCEHandler.Builder(this)
.addCommaSeparatedEmailAddresses("crashreports@openseizuredetector.org.uk,")
.build();
//int i = 5/0; // Force exception to test handler.
// Create a wake lock, but don't use it until the service is started.
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
"OSD:WakeLock");
}
/**

View File

@@ -49,6 +49,8 @@ import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.rohitss.uceh.UCEHandler;
import java.util.Timer;
import java.util.TimerTask;
@@ -82,7 +84,11 @@ public class StartupActivity extends Activity {
Log.i(TAG,"onCreate()");
// Set our custom uncaught exception handler to report issues.
Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(StartupActivity.this));
//Thread.setDefaultUncaughtExceptionHandler(new OsdUncaughtExceptionHandler(StartupActivity.this));
new UCEHandler.Builder(this)
.addCommaSeparatedEmailAddresses("crashreports@openseizuredetector.org.uk,")
.build();
mHandler = new Handler();
mUtil = new OsdUtil(this, mHandler);
@@ -103,6 +109,10 @@ public class StartupActivity extends Activity {
PreferenceManager.setDefaultValues(this, R.xml.camera_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.general_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.network_datasource_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.pebble_datasource_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.garmin_datasource_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.seizure_detector_prefs, true);
PreferenceManager.setDefaultValues(this, R.xml.network_passive_datasource_prefs, true);
Button b;
@@ -174,6 +184,14 @@ public class StartupActivity extends Activity {
mUtil.writeToSysLogFile("StartupActivity.onStart()");
TextView tv;
if (mUtil.arePermissionsOK()) {
Log.i(TAG,"onStart() - Permissions OK");
} else {
Log.i(TAG,"onStart() - Permissions Not OK - requesting them");
mUtil.requestPermissions(this);
}
String versionName = mUtil.getAppVersionName();
tv = (TextView) findViewById(R.id.appNameTv);
tv.setText("OpenSeizureDetector V" + versionName);
@@ -198,6 +216,8 @@ public class StartupActivity extends Activity {
mUsingPebbleDataSource = true;
}
if (mUtil.isServerRunning()) {
Log.i(TAG, "onStart() - server running - stopping it");
mUtil.writeToSysLogFile("StartupActivity.onStart() - server already running - stopping it.");

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:fadeScrollbars="false"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/ask_for_error_log"
android:textColor="#212121"
android:textSize="18sp"/>
<Button
android:id="@+id/button_view_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="View Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_copy_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Copy Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_share_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Share Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_email_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Email Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_save_error_log"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Save Error Log"
android:textColor="#212121"/>
<Button
android:id="@+id/button_close_app"
android:layout_width="150dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Close App"
android:textColor="#212121"/>
</LinearLayout>
</ScrollView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/copyright_info"
android:textColor="#212121"
android:textSize="14sp"/>
</LinearLayout>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OpenSeizureDetector</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
<string name="ask_for_error_log">Sorry, OpenSeizureDetector Has Crashed. Please Email this log file to us so we can work out what happened and fix it.\nThanks, Graham.</string>
<string name="email_welcome_note">Dear OpenSeizureDetector,\n\nApplication is just crashed, please check following error log for more details.\n\n\n</string>
<string name="copyright_info">OpenSeizureDetector (Using UCE Handler\nCopyright © 2018 Rohit Sahebrao Surwase.)</string>
</resources>

View File

@@ -19,6 +19,7 @@ allprojects {
url 'https://maven.google.com/'
name 'Google'
}
//maven { url 'https://jitpack.io' }
}
}