/*
* Copyright 2014 Bevbot LLC <info@bevbot.com>
*
* This file is part of the Kegtab package from the Kegbot project. For
* more information on Kegtab or Kegbot, see <http://kegbot.org/>.
*
* Kegtab is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free
* Software Foundation, version 2.
*
* Kegtab 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 Kegtab. If not, see <http://www.gnu.org/licenses/>.
*/
/**
*
*/
package org.kegbot.app;
import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.google.common.base.Strings;
import org.kegbot.app.config.AppConfiguration;
import org.kegbot.app.util.CheckinClient;
import org.kegbot.core.KegbotCore;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import butterknife.ButterKnife;
/**
* Bug report activity.
*
* @author mike wakerly (opensource@hoho.com)
*/
public class BugreportActivity extends Activity {
private static final String TAG = BugreportActivity.class.getSimpleName();
private static final int INPUT_BUFFER_SIZE = 1024 * 64;
private static final String BUGREPORT_FILENAME = "bugreport.txt";
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private AppConfiguration mConfig;
private ProgressBar mProgressBar;
private TextView mMessageText;
private TextView mDetailText;
private EditText mEmailText;
private File mBugreportFile;
private Button mButton;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bugreport_activity);
mConfig = ((KegbotApplication) getApplicationContext()).getConfig();
mButton = ButterKnife.findById(this, R.id.bugreportButton);
mProgressBar = ButterKnife.findById(this, R.id.bugreportProgress);
mProgressBar.setIndeterminate(true);
mMessageText = ButterKnife.findById(this, R.id.bugreportMessage);
mDetailText = ButterKnife.findById(this, R.id.bugreportDetail);
mEmailText = ButterKnife.findById(this, R.id.bugreportEmail);
}
@Override
protected void onStart() {
super.onStart();
if (mBugreportFile != null) {
showBugreportReady();
} else {
showIdle();
}
final ActionBar bar = getActionBar();
if (bar != null) {
bar.setTitle("");
}
final String email = mConfig.getEmailAddress();
if (!Strings.isNullOrEmpty(email)) {
mEmailText.setText(email);
}
}
private void showIdle() {
mButton.setEnabled(true);
mButton.setText(R.string.bugreport_button_idle);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
collectBugreport();
}
});
mMessageText.setText(R.string.bugreport_message_idle);
mDetailText.setVisibility(View.GONE);
mProgressBar.setVisibility(View.INVISIBLE);
mEmailText.setVisibility(View.GONE);
}
private void showCollectingBugreport() {
mButton.setEnabled(false);
mMessageText.setText(R.string.bugreport_message_running);
mDetailText.setVisibility(View.GONE);
mEmailText.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
}
private void showBugreportReady() {
mButton.setEnabled(true);
mButton.setText(R.string.bugreport_button_ready);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
submitBugreport();
}
});
mMessageText.setEnabled(true);
mMessageText.setText(R.string.bugreport_message_ready);
mButton.setEnabled(true);
mProgressBar.setVisibility(View.INVISIBLE);
mDetailText.setText("");
mDetailText.setVisibility(View.VISIBLE);
mDetailText.setEnabled(true);
mEmailText.setVisibility(View.VISIBLE);
mEmailText.setEnabled(true);
}
private void showSubmittingBugreport() {
mButton.setEnabled(false);
mMessageText.setText(R.string.bugreport_message_running);
mDetailText.setEnabled(false);
mEmailText.setEnabled(false);
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setIndeterminate(true);
}
private void showFinished() {
mButton.setEnabled(false);
mMessageText.setText(R.string.bugreport_message_submitted);
mDetailText.setEnabled(false);
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setProgress(100);
mProgressBar.setIndeterminate(false);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
finish();
}
}, 3000);
}
private void showError(final String errorMessage) {
mHandler.post(new Runnable() {
@Override
public void run() {
Log.e(TAG, errorMessage);
showIdle();
mMessageText.setText(errorMessage);
}
});
}
private void collectBugreport() {
showCollectingBugreport();
new CollectBugreportAsyncTask().executeOnExecutor(mExecutor, (Void) null);
}
private void submitBugreport() {
showSubmittingBugreport();
new SubmitBugreportAsyncTask().execute(mBugreportFile);
}
private class CollectBugreportAsyncTask extends AsyncTask<Void, Void, File> {
@Override
protected File doInBackground(Void... params) {
final FileOutputStream out;
try {
out = openFileOutput(BUGREPORT_FILENAME, MODE_PRIVATE);
} catch (FileNotFoundException e) {
showError("Could not create bugreport file, error: " + e);
return null;
}
try {
PrintWriter writer = new PrintWriter(out);
writer.println("Kegbot bugreport.");
writer.println();
writer.println("--- Kegbot core ---");
writer.println();
writer.flush();
final KegbotCore core = KegbotCore.getRunningInstance(BugreportActivity.this);
if (core == null) {
writer.println("Not running.");
writer.println();
} else {
core.dump(writer);
}
writer.println("--- System logs ---");
writer.println();
writer.flush();
try {
getDeviceLogs(out);
writer.flush();
} catch (IOException e) {
showError("Error grabbing bugreport: " + e);
}
writer.println("--- (end of bugreport) ---");
writer.flush();
writer.close();
} finally {
try {
out.close();
} catch (IOException e) {
// Ignore.
}
}
return getFileStreamPath(BUGREPORT_FILENAME);
}
@Override
protected void onCancelled() {
super.onCancelled();
}
@Override
protected void onPostExecute(File file) {
mBugreportFile = file;
if (mBugreportFile == null) {
// Presume we called showError() somewhere.
return;
}
showBugreportReady();
}
}
private class SubmitBugreportAsyncTask extends AsyncTask<File, Void, Exception> {
@Override
protected Exception doInBackground(File... params) {
final String messageText = Strings.nullToEmpty(mDetailText.getText().toString());
final CheckinClient client = CheckinClient.fromContext(getApplicationContext());
final String email = mEmailText.getText().toString();
if (!Strings.isNullOrEmpty(email)) {
mConfig.setEmailAddress(email);
}
try {
client.submitBugreport(messageText, mBugreportFile, email);
} catch (Exception e) {
return e;
}
return null;
}
@Override
protected void onPostExecute(Exception result) {
if (result == null) {
showFinished();
} else {
showError("Error submitting bugreport: " + result.getMessage());
}
}
}
private static void getDeviceLogs(OutputStream outputStream) throws IOException {
final String command = "logcat -v time -d";
Log.d(TAG, "Running command: " + command);
final Process process = Runtime.getRuntime().exec(command);
final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process
.getInputStream()), INPUT_BUFFER_SIZE);
while (true) {
final String line = bufferedReader.readLine();
if (line == null) {
break;
}
outputStream.write(line.getBytes());
outputStream.write('\n');
}
}
public static void startBugreportActivity(Context context) {
Intent intent = new Intent(context, BugreportActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);
PinActivity.startThroughPinActivity(context, intent);
}
}