/* * Copyright 2015 Daniel Dittmar * * 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 dan.dit.whatsthat.system; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.Window; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import dan.dit.whatsthat.BuildConfig; import dan.dit.whatsthat.R; import dan.dit.whatsthat.testsubject.TestSubject; import dan.dit.whatsthat.util.image.ExternalStorage; /** * Emergency activity when there was an uncaught exception that shut down the app. * Enables the user to send me an email containing an attached log extract. * Source: * http://stackoverflow.com/questions/19897628/need-to-handle-uncaught-exception-and-send-log-file */ public class SendLog extends Activity implements View.OnClickListener { private static final String LOGS_DIRECTORY_NAME = "logs"; public static final String KEY_CAUSE = "dan.dit.whatsthat.CRASH_CAUSE"; private String mCause; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature (Window.FEATURE_NO_TITLE); // make a dialog without a titlebar setFinishOnTouchOutside (false); // prevent users from dismissing the dialog by tapping outside setContentView (R.layout.send_log); findViewById(R.id.send).setOnClickListener(this); findViewById(R.id.cancel).setOnClickListener(this); Intent intent = getIntent(); if (intent != null) { Bundle data = intent.getExtras(); if (data != null) { mCause = data.getString(KEY_CAUSE, ""); } } } @Override public void onClick (View v) { if (v.getId() == R.id.send) { sendLogFile(); } else { finish(); } } private void sendLogFile () { try { String fullName = extractLogToFile(); if (fullName == null) { return; } Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("plain/text"); intent.putExtra(Intent.EXTRA_EMAIL, new String[]{TestSubject.EMAIL_ON_ERROR}); intent.putExtra(Intent.EXTRA_SUBJECT, "WhatsThat log file"); intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + fullName)); intent.putExtra(Intent.EXTRA_TEXT, "Log file attached."); // do this so some email clients don't complain about empty body. startActivity(intent); } catch (Exception e) { // something even worse happened, just finish } finally { finish(); // no more worries, you are out } } private String extractLogToFile() { PackageManager manager = this.getPackageManager(); PackageInfo info = null; try { info = manager.getPackageInfo (this.getPackageName(), 0); } catch (PackageManager.NameNotFoundException e2) { // we got no package name, whatever } String model = Build.MODEL; if (!model.startsWith(Build.MANUFACTURER)) model = Build.MANUFACTURER + " " + model; // Make file name - file must be saved to external storage or it wont be readable by // the email app. String path = ExternalStorage.getExternalStoragePathIfMounted(LOGS_DIRECTORY_NAME); if (path == null) { return null; } File dir = new File(path); if (!dir.mkdirs() && !dir.isDirectory()) { // not created and not a directory return null; } String fullName = path + "/error"; // Extract to file. File file = new File (fullName); InputStreamReader reader = null; FileWriter writer = null; try { // For Android 4.0 and earlier, you will get all app's log output, so filter it to // mostly limit it to your app's output. In later versions, the filtering isn't needed. final String cmd = (Build.VERSION.SDK_INT <= Build.VERSION_CODES .ICE_CREAM_SANDWICH_MR1) ? "logcat -d -v time WhatsThat:v dalvikvm:v System.err:v *:s" : "logcat -d -v time"; // write output stream writer = new FileWriter (file); writer.write ("Android version: " + Build.VERSION.SDK_INT + "\n"); writer.write ("Device: " + model + "\n"); writer.write ("App version: " + (info == null ? "(null)" : info.versionCode) + "\n"); writer.write("Cause: " + (mCause == null ? "(null)" : mCause)); if (BuildConfig.DEBUG) { // get input stream try { Process process = Runtime.getRuntime().exec(cmd); reader = new InputStreamReader(process.getInputStream()); char[] buffer = new char[10000]; do { int n = reader.read(buffer, 0, buffer.length); if (n == -1) break; writer.write(buffer, 0, n); } while (true); reader.close(); } catch (Exception e) { Log.e("HomeStuff", "Critical, exception during getting error log in debug " + "config: " + e); } } writer.close(); } catch (IOException e) { if (writer != null) try { writer.close(); } catch (IOException e1) { // failed closing after exception, ignore } if (reader != null) try { reader.close(); } catch (IOException e1) { // failed closing after exception, ignore } Log.e("HomeStuff", "Failed failing. Literally .. could not write log file: " + e); return null; } return fullName; } }