Java tutorial
/* * Copyright (C) 2013 Slimroms http://www.slimroms.net * Copyright (C) 2014 LegacyXperia Project * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * 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 program. If not, see <http://www.gnu.org/licenses/>. */ package org.legacyxperia.center; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.Toast; public class BugReport extends Fragment { private static final String LOG_TAG = "DeviceInfoSettings"; private LinearLayout bugreport; private LinearLayout bugtracker; private String mStrDevice; private boolean su = false; private static final String FILENAME_PROC_VERSION = "/proc/version"; public File path; public String zipfile; public String logfile; public String last_kmsgfile; public String kmsgfile; public String radiofile; public String systemfile; Process superUser; DataOutputStream ds; byte[] buf = new byte[1024]; private final View.OnClickListener mActionLayouts = new View.OnClickListener() { @Override public void onClick(View v) { if (v == bugreport) { bugReport(); } else if (v == bugtracker) { launchUrl("https://github.com/LegacyXperia/local_manifests/issues?state=open"); } } }; private void launchUrl(String url) { final Uri uriUrl = Uri.parse(url); final Intent openUrl = new Intent(Intent.ACTION_VIEW, uriUrl); getActivity().startActivity(openUrl); } private void toast(String text) { // Easy toasts for all! Toast toast = Toast.makeText(getView().getContext(), text, Toast.LENGTH_SHORT); toast.show(); } private void bugReport() { try { // Collect system information FileInputStream fstream = new FileInputStream("/system/build.prop"); DataInputStream in = new DataInputStream(fstream); BufferedReader br = new BufferedReader(new InputStreamReader(in)); String strLine; while ((strLine = br.readLine()) != null) { String[] line = strLine.split("="); if (line[0].equalsIgnoreCase("ro.modversion")) { mStrDevice = line[1]; } } in.close(); } catch (Exception e) { Toast.makeText(getView().getContext(), getString(R.string.system_prop_error), Toast.LENGTH_LONG).show(); e.printStackTrace(); } String kernel = getFormattedKernelVersion(); // Initialize log files File extdir = Environment.getExternalStorageDirectory(); path = new File(extdir + "/LX/bugreport"); File savefile = new File(path + "/system.log"); File logcat = new File(path + "/logcat.log"); File last_kmsg = new File(path + "/last_kmsg.log"); File kmsg = new File(path + "/kmsg.log"); File radio = new File(path + "/radio.log"); File zip = new File(extdir + "/LX/bugreport.zip"); systemfile = savefile.toString(); logfile = logcat.toString(); last_kmsgfile = last_kmsg.toString(); kmsgfile = kmsg.toString(); radiofile = radio.toString(); zipfile = zip.toString(); // Cleanup old logs if (sdAvailable() == 2) { try { // Create directory if it doesn't exist if (!path.exists()) { path.mkdirs(); } if (savefile.exists()) { savefile.delete(); } if (logcat.exists()) { logcat.delete(); } if (zip.exists()) { zip.delete(); } if (last_kmsg.exists()) { last_kmsg.delete(); } if (kmsg.exists()) { kmsg.delete(); } if (radio.exists()) { radio.delete(); } // Create system.log and output device info to it FileWriter outstream = new FileWriter(savefile); BufferedWriter save = new BufferedWriter(outstream); save.write("Device: " + mStrDevice + '\n' + "Kernel: " + kernel); save.close(); outstream.close(); // Get system logs and write them to files getLogs("logcat -d -f " + logcat + " *:V\n"); getLogs("cat /proc/last_kmsg > " + last_kmsgfile + "\n"); getLogs("cat /proc/kmsg > " + kmsgfile + "\n"); getLogs("logcat -b radio -d -f " + radio + "\n"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } // Create zip file if (savefile.exists() && logcat.exists() && last_kmsg.exists() && kmsg.exists() && radio.exists()) { boolean zipCreated = zip(); if (zipCreated == true) { dialog(true); } else { dialog(false); } } } catch (IOException e) { e.printStackTrace(); } } else { toast(getResources().getString(R.string.sizer_message_sdnowrite)); } } private short sdAvailable() { // Check if SD card is available // Taken from developer.android.com short mExternalStorageAvailable = 0; String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { // We can read and write the media mExternalStorageAvailable = 2; } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { // We can only read the media mExternalStorageAvailable = 1; } else { // Something else is wrong. It may be one of many other states, but // all we need to know is we can neither read nor write mExternalStorageAvailable = 0; } return mExternalStorageAvailable; } private static String getFormattedKernelVersion() { try { return formatKernelVersion(readLine(FILENAME_PROC_VERSION)); } catch (IOException e) { Log.e(LOG_TAG, "IO Exception when getting kernel version", e); return "Unavailable"; } } public static String formatKernelVersion(String rawKernelVersion) { final String PROC_VERSION_REGEX = "Linux version (\\S+) " + /* group 1: "3.0.31-g6fb96c9" */ "\\((\\S+?)\\) " + /* group 2: "x@y.com" (kernel builder) */ "(?:\\(gcc.+? \\)) " + /* ignore: GCC version information */ "(#\\d+) " + /* group 3: "#1" */ "(?:.*?)?" + /* ignore: optional SMP, PREEMPT, and any CONFIG_FLAGS */ "((Sun|Mon|Tue|Wed|Thu|Fri|Sat).+)"; /* group 4: "Thu Jun 28 11:02:39 PDT 2012" */ Matcher m = Pattern.compile(PROC_VERSION_REGEX).matcher(rawKernelVersion); if (!m.matches()) { Log.e(LOG_TAG, "Regex did not match on /proc/version: " + rawKernelVersion); return "Unavailable"; } else if (m.groupCount() < 4) { Log.e(LOG_TAG, "Regex match on /proc/version only returned " + m.groupCount() + " groups"); return "Unavailable"; } return m.group(1) + " " + m.group(2) + " " + m.group(3); } private static String readLine(String filename) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(filename), 256); try { return reader.readLine(); } finally { reader.close(); } } private boolean zip() { String[] source = { systemfile, logfile, last_kmsgfile, kmsgfile, radiofile }; try { ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipfile)); for (int i = 0; i < source.length; i++) { String file = source[i].substring(source[i].lastIndexOf("/"), source[i].length()); FileInputStream in = new FileInputStream(source[i]); out.putNextEntry(new ZipEntry(file)); int len; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); } out.closeEntry(); in.close(); } out.close(); } catch (Exception e) { e.printStackTrace(); return false; } return true; } private void getLogs(String command) { try { Process process = Runtime.getRuntime().exec("su"); DataOutputStream os = new DataOutputStream(process.getOutputStream()); os.writeBytes(command); os.writeBytes("exit\n"); os.flush(); os.close(); } catch (IOException e) { e.printStackTrace(); } } private void dialog(boolean success) { final AlertDialog.Builder alert = new AlertDialog.Builder(getActivity()); if (success == true) { alert.setMessage(R.string.report_infosuccess).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // action for ok dialog.cancel(); } }); } else { alert.setMessage(R.string.report_infofail).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { // action for ok dialog.cancel(); } }); } alert.show(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); bugreport = (LinearLayout) getView().findViewById(R.id.lx_bugreport); bugreport.setOnClickListener(mActionLayouts); bugtracker = (LinearLayout) getView().findViewById(R.id.lx_bugtracker); bugtracker.setOnClickListener(mActionLayouts); // Request su try { if (!su) { superUser = Runtime.getRuntime().exec("su"); ds = new DataOutputStream(superUser.getOutputStream()); ds.writeBytes("mount -o remount,rw /system" + "\n"); ds.flush(); su = true; } } catch (final IOException e) { e.printStackTrace(); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.lx_bugreport, container, false); return view; } }