package org.softeg.slartus.forpdaplus.common; import android.content.Context; import android.text.TextUtils; import android.util.Log; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; import org.apache.http.MalformedChunkCodingException; import org.apache.http.NoHttpResponseException; import org.apache.http.client.ClientProtocolException; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.conn.HttpHostConnectException; import org.softeg.slartus.forpdacommon.NotReportException; import org.softeg.slartus.forpdacommon.ShowInBrowserException; import org.softeg.slartus.forpdaplus.App; import org.softeg.slartus.forpdaplus.R; import org.softeg.slartus.forpdaplus.classes.Exceptions.MessageInfoException; import org.softeg.slartus.forpdaplus.classes.ShowInBrowserDialog; import java.net.SocketException; import java.net.SocketTimeoutException; public final class AppLog { private static final String TAG = "AppLog"; public static void e(Throwable ex) { e(null, ex, null); } public static void e(Context context, Throwable ex) { e(context, ex, null); } public static void toastE(Context context, Throwable ex) { String message=ex.getLocalizedMessage(); if(TextUtils.isEmpty(message)) message=ex.getMessage(); if(TextUtils.isEmpty(message)) message=ex.toString(); android.util.Log.e(TAG, ex.toString()); try { Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } catch (Throwable ignoredEx) { } } public static void e(Context context, Throwable ex, Runnable netExceptionAction) { String exLocation = getLocation(); android.util.Log.e(TAG, exLocation + ex); if (tryShowNetException(context != null ? context : App.getInstance(), ex, netExceptionAction)) return; String message = ex.getMessage(); if (TextUtils.isEmpty(message)) message = ex.toString(); if (ex.getClass() == ShowInBrowserException.class) { ShowInBrowserDialog.showDialog(context, (ShowInBrowserException) ex); } else if (ex instanceof NotReportException) { new MaterialDialog.Builder(context) .title(R.string.error) .content(message) .positiveText(R.string.ok) .show(); } else if (ex.getClass() == MessageInfoException.class) { MessageInfoException messageInfoException = (MessageInfoException) ex; new MaterialDialog.Builder(context) .title(messageInfoException.Title) .content(messageInfoException.Text) .positiveText(R.string.ok) .show(); } else { org.acra.ACRA.getErrorReporter().handleException(ex); } } public static boolean tryShowNetException(Context context, Throwable ex, final Runnable netExceptionAction) { try { String message = getLocalizedMessage(ex, null); if (message == null) return false; MaterialDialog.Builder builder = new MaterialDialog.Builder(context) .title(R.string.check_connection) .content(message) .positiveText(R.string.ok); if (netExceptionAction != null) { builder.negativeText(R.string.repeat) .callback(new MaterialDialog.ButtonCallback() { @Override public void onNegative(MaterialDialog dialog) { netExceptionAction.run(); } }); } builder.show(); return true; } catch (Throwable loggedEx) { android.util.Log.e(TAG, ex.toString()); return true; } } public static String getLocalizedMessage(Throwable ex, String defaultValue) { if (isHostUnavailableException(ex)) return App.getContext().getString(R.string.server_not_available_or_not_respond); if (isTimeOutException(ex)) return App.getContext().getString(R.string.exceeded_timeout); if (isException(ex, MalformedChunkCodingException.class)) return App.getContext().getString(R.string.server_failed_to_respond); if (isException(ex, SocketException.class)) return App.getContext().getString(R.string.connection_lost); return defaultValue; } private static Boolean isException(Throwable ex, Class c) { return isException(ex, false, c); } private static Boolean isException(Throwable ex, Boolean isCause, Class c) { return ex != null && (ex.getClass() == c || (!isCause && isException(ex.getCause(), true, c))); } private static Boolean isHostUnavailableException(Throwable ex) { return isHostUnavailableException(ex, false); } private static Boolean isHostUnavailableException(Throwable ex, Boolean isCause) { if (ex == null) return false; Class clazz = ex.getClass(); return clazz == java.net.UnknownHostException.class || clazz == HttpHostConnectException.class || clazz == ClientProtocolException.class || clazz == NoHttpResponseException.class || clazz == org.apache.http.conn.HttpHostConnectException.class || (!isCause && isHostUnavailableException(ex.getCause(), true)); } private static Boolean isTimeOutException(Throwable ex) { return isTimeOutException(ex, false); } private static Boolean isTimeOutException(Throwable ex, Boolean isCause) { if (ex == null) return false; return (ex.getClass() == ConnectTimeoutException.class) || ex.getClass() == SocketTimeoutException.class || (ex.getClass() == SocketException.class && "recvfrom failed: ETIMEDOUT (Connection timed out)".equals(ex.getMessage())) || (!isCause && isTimeOutException(ex.getCause(), true)); } public static void i(Context mContext, Throwable ex) { Log.i(TAG, ex.toString()); } public static void eToast(Context context, Throwable e) { toastE(context, e); } private static String getLocation() { final String className = Log.class.getName(); final StackTraceElement[] traces = Thread.currentThread() .getStackTrace(); boolean found = false; for (int i = 0; i < traces.length; i++) { StackTraceElement trace = traces[i]; try { if (found) { if (!trace.getClassName().startsWith(className)) { Class<?> clazz = Class.forName(trace.getClassName()); return "[" + getClassName(clazz) + ":" + trace.getMethodName() + ":" + trace.getLineNumber() + "]: "; } } else if (trace.getClassName().startsWith(className)) { found = true; continue; } } catch (ClassNotFoundException e) { } } return "[]: "; } private static String getClassName(Class<?> clazz) { if (clazz != null) { if (!TextUtils.isEmpty(clazz.getName())) { return clazz.getName(); } if (!TextUtils.isEmpty(clazz.getSimpleName())) { return clazz.getSimpleName(); } return getClassName(clazz.getEnclosingClass()); } return ""; } }