/*
* AndFHEM - Open Source Android application to control a FHEM home automation
* server.
*
* Copyright (c) 2011, Matthias Klass or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU GENERAL PUBLIC LICENSE
* for more details.
*
* You should have received a copy of the GNU GENERAL PUBLIC LICENSE
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package li.klass.fhem.error;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.io.CharStreams;
import com.google.common.io.Files;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import li.klass.fhem.AndFHEMApplication;
import li.klass.fhem.R;
import li.klass.fhem.util.CloseableUtil;
import li.klass.fhem.util.DialogUtil;
import static com.google.common.collect.Lists.newArrayList;
import static li.klass.fhem.util.StackTraceUtil.exceptionAsString;
import static li.klass.fhem.util.StackTraceUtil.whereAmI;
public class ErrorHolder {
private static final String TAG = ErrorHolder.class.getName();
private volatile transient Exception errorException;
private volatile transient String errorMessage;
public static ErrorHolder ERROR_HOLDER = new ErrorHolder();
private ErrorHolder() {
}
public static void setError(Exception exception, String errorMessage) {
ErrorHolder holder = ErrorHolder.ERROR_HOLDER;
holder.errorException = exception;
holder.errorMessage = errorMessage;
}
public static void setError(String errorMessage) {
setError(null, errorMessage);
}
public static String getText() {
ErrorHolder holder = ErrorHolder.ERROR_HOLDER;
String text = holder.errorMessage;
String exceptionString;
if (holder.errorException != null) {
exceptionString = exceptionAsString(holder.errorException);
} else {
exceptionString = whereAmI();
}
if (holder.errorException != null) {
text += "\r\n --------- \r\n\r\n" + exceptionString;
}
return text;
}
public static void sendLastErrorAsMail(final Context context) {
DialogUtil.showConfirmBox(context, R.string.error_send,
R.string.error_send_content, new DialogUtil.AlertOnClickListener() {
@Override
public void onClick() {
handleSendLastError(context);
}
});
}
private static void handleSendLastError(Context context) {
if (!handleExternalStorageState(context)) return;
try {
String lastError = ErrorHolder.getText();
if (lastError == null) {
DialogUtil.showAlertDialog(context, R.string.error_send, R.string.error_send_no_error);
return;
}
File attachment = writeToDisk(context, lastError);
sendMail(context, "Send last error", "Error encountered!", deviceInformation(), Uri.fromFile(attachment));
} catch (Exception e) {
Log.e(TAG, "error while sending last error");
}
}
@SuppressWarnings("unchecked")
public static void sendApplicationLogAsMail(Context context) {
if (!handleExternalStorageState(context)) return;
try {
File file = writeApplicationLogToDisk(context);
sendMail(context, context.getString(R.string.application_log_send), "Send app log",
deviceInformation(), Uri.fromFile(file));
} catch (Exception e) {
Log.e(TAG, "Error while reading application log", e);
}
}
private static void sendMail(Context context, String chooserText, String subject, String text,
Uri attachment) throws IOException {
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_EMAIL, new String[]{AndFHEMApplication.ANDFHEM_MAIL});
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
intent.putExtra(Intent.EXTRA_TEXT, text);
intent.putExtra(android.content.Intent.EXTRA_STREAM, attachment);
if (context == null) return;
context.startActivity(Intent.createChooser(intent, chooserText));
}
private static File writeApplicationLogToDisk(Context context) throws IOException {
InputStreamReader reader = null;
try {
File outputDir = context.getCacheDir();
File outputFile = File.createTempFile("andFHEM-", "log", outputDir);
outputFile.deleteOnExit();
Process process = Runtime.getRuntime().exec("logcat -d");
reader = new InputStreamReader(process.getInputStream(), Charsets.UTF_8);
List<String> logLines = CharStreams.readLines(reader);
String log = Joiner.on("\r\n").join(logLines);
return writeToDisk(context, log);
} finally {
CloseableUtil.close(reader);
}
}
private static File writeToDisk(Context context, String content) throws IOException {
File outputDir = context.getExternalFilesDir(null);
File outputFile = File.createTempFile("andFHEM-", ".log", outputDir);
outputFile.setReadable(true, true);
outputFile.deleteOnExit();
Files.write(content, outputFile, Charsets.UTF_8);
return outputFile;
}
private static String deviceInformation() {
return Joiner.on("\r\n").join(newArrayList(
"Device information:",
"OS-Version: " + System.getProperty("os.version"),
"API-Level: " + Build.VERSION.SDK_INT,
"Device: " + android.os.Build.DEVICE,
"Manufacturer: " + Build.MANUFACTURER,
"Model: " + android.os.Build.MODEL,
"Product: " + android.os.Build.PRODUCT,
"App-version: " + AndFHEMApplication.getApplication().getCurrentApplicationVersion()
));
}
private static boolean handleExternalStorageState(Context context) {
String state = Environment.getExternalStorageState();
if (!state.equals(Environment.MEDIA_MOUNTED)) {
DialogUtil.showAlertDialog(context, R.string.error, R.string.errorExternalStorageNotPresent);
return false;
}
return true;
}
}