package de.theknut.xposedgelsettings.ui; import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import de.theknut.xposedgelsettings.R; import de.theknut.xposedgelsettings.hooks.Common; import de.theknut.xposedgelsettings.ui.preferences.SwitchCompatPreference; @SuppressLint("WorldReadableFiles") public class FragmentSettings extends FragmentBase { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { super.onCreateView(inflater, container, savedInstanceState); View rootView = inflater.inflate(R.layout.options_fragment, container, false); addPreferencesFromResource(R.xml.settings_fragment); findPreference("nobackgroundimage").setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { CommonUI.NO_BACKGROUND_IMAGE = (Boolean) newValue; return true; } }); findPreference("forceenglishlocale").setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { mContext.getSharedPreferences(Common.PREFERENCES_NAME, Context.MODE_WORLD_READABLE) .edit() .putBoolean("forceenglishlocale", (Boolean) newValue) .commit(); CommonUI.restartActivity(); return true; } }); this.findPreference("autoblurimage").setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @SuppressWarnings("deprecation") @Override public boolean onPreferenceChange(Preference preference, Object newValue) { CommonUI.needFullReboot = true; Toast.makeText(mContext, R.string.toast_full_reboot, Toast.LENGTH_LONG).show(); if ((Boolean) newValue) { Intent myIntent = new Intent(); myIntent.setAction(Intent.ACTION_WALLPAPER_CHANGED); mContext.sendBroadcast(myIntent); } return true; } }); this.findPreference("showchangelog").setOnPreferenceClickListener(new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { Changelog cl = new Changelog(mContext); cl.getFullLogDialog().show(); return true; } }); final SwitchCompatPreference debugPreference = (SwitchCompatPreference) this.findPreference("debug"); debugPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { @Override public boolean onPreferenceChange(Preference preference, Object newValue) { if ((Boolean) newValue) { new MaterialDialog.Builder(mActivity) .theme(Theme.DARK) .cancelable(false) .title(R.string.alert_debug_logging_activated_title) .content(R.string.alert_debug_logging_activated_summary) .positiveText(android.R.string.ok) .callback(new MaterialDialog.ButtonCallback() { @Override public void onPositive(MaterialDialog materialDialog) { CommonUI.restartLauncher(false); } }) .build() .show(); } return true; } }); this.findPreference("sendbugreport").setOnPreferenceClickListener(new OnPreferenceClickListener() { @SuppressWarnings("deprecation") @SuppressLint("SdCardPath") @Override public boolean onPreferenceClick(Preference preference) { boolean debugLoggingEnabled = mContext.getSharedPreferences(Common.PREFERENCES_NAME, Context.MODE_WORLD_READABLE).getBoolean("debug", false); if (!debugLoggingEnabled) { new MaterialDialog.Builder(mActivity) .theme(Theme.DARK) .cancelable(false) .autoDismiss(true) .title(R.string.alert_debug_logging_not_activated_title) .content(R.string.alert_debug_logging_not_activated_summary) .positiveText(android.R.string.ok) .build() .show(); return false; } String pathDebugLog = null; String pathXGELSPrefs = mContext.getApplicationInfo().dataDir + "/shared_prefs/de.theknut.xposedgelsettings_preferences.xml"; try { Context xposedInstallerContext = mContext.createPackageContext("de.robv.android.xposed.installer", Context.CONTEXT_IGNORE_SECURITY); pathDebugLog = xposedInstallerContext.getApplicationInfo().dataDir + "/log/error.log"; } catch (Exception e) { e.printStackTrace(); pathDebugLog = "/data/data/de.robv.android.xposed.installer/log/error.log"; } if (!new File(pathDebugLog).exists()) { pathDebugLog.replace("error.log", "debug.log"); } String logfilePath = "/mnt/sdcard/XposedGELSettings/logs/logcat.log"; File logfile = new File(logfilePath); if (logfile.exists()) { logfile.delete(); } logfile.getParentFile().mkdirs(); try { logfile.createNewFile(); Process process = Runtime.getRuntime().exec("logcat -v time -d"); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream())); StringBuilder log = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { log.append(line).append('\n'); } FileWriter out = new FileWriter(logfile); out.write(log.toString()); out.close(); } catch (IOException e) {} File debugLogFile = new File(pathDebugLog); File xgelsPrefsFile = new File(pathXGELSPrefs); if (debugLogFile.exists() && xgelsPrefsFile.exists()) { ArrayList<Uri> uris = new ArrayList<>(); uris.add(save(pathDebugLog)); uris.add(save(pathXGELSPrefs)); if (logfile.exists()) { uris.add(Uri.fromFile(logfile)); } char ls = '\n'; StringBuilder deviceInfo = new StringBuilder(); deviceInfo.append("Manufacturer: " + Build.MANUFACTURER).append(ls); deviceInfo.append("Device: " + Build.DEVICE).append(ls); deviceInfo.append("Model: " + Build.MODEL).append(ls); deviceInfo.append("OS: " + Build.DISPLAY + " (" + Build.VERSION.RELEASE + ")").append(ls); String version = null; try { ArrayList<String> skuList = new ArrayList<String>(); Collections.addAll(skuList, mContext.getResources().getStringArray(R.array.premiumValues)); String additional; try { additional = InAppPurchase.isPremium ? " | " + InAppPurchase.mHelper.getOrderId(skuList) : ""; } catch (Exception e) { additional = e.getMessage(); } PackageManager pkgMgr = mContext.getPackageManager(); PackageInfo packageInfo = pkgMgr.getPackageInfo(mContext.getPackageName(), 0); version = "XGELS" + (InAppPurchase.isPremium ? " Premium: " : ": ") + packageInfo.versionName + " (" + packageInfo.versionCode + ")" + additional; deviceInfo.append(version).append(ls); packageInfo = pkgMgr.getPackageInfo("de.robv.android.xposed.installer", 0); version = "Xposed: " + packageInfo.versionName + " (" + packageInfo.versionCode + ")"; deviceInfo.append(version).append(ls); packageInfo = pkgMgr.getPackageInfo(Common.GEL_PACKAGE, 0); version = "Google Search: " + packageInfo.versionName + " (" + packageInfo.versionCode + ")"; deviceInfo.append(version).append(ls); Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); ResolveInfo resolveInfo = pkgMgr.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); deviceInfo.append("Launcher: " + resolveInfo.activityInfo.name + " (" + resolveInfo.activityInfo.packageName + ")").append(ls); } catch (NameNotFoundException e) { // shouldn't be here but lets prevent this from crashing... } Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); String[] recipients = {"theknutcoding+xgels.bugreport@gmail.com"}; intent.putExtra(Intent.EXTRA_EMAIL, recipients); intent.putExtra(Intent.EXTRA_SUBJECT, "XGELS Debug log"); intent.putExtra(Intent.EXTRA_TEXT, deviceInfo.toString() + '\n' + '\n' + "Bug report description: <short description>" + '\n' + '\n' + "Steps to reproduce: <repro steps>" + '\n' + '\n'); intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); intent.setType("text/html"); startActivityForResult(Intent.createChooser(intent, "Send mail"), 0); debugPreference.setChecked(false); CommonUI.restartLauncher(false); return true; } Toast.makeText(mContext, getString(R.string.toast_no_log_found), Toast.LENGTH_LONG).show(); return false; } }); PreferenceScreen preferenceScreen = getPreferenceScreen(); if (!InAppPurchase.isPremium) { this.findPreference("autoblurimage").setEnabled(false); } else { preferenceScreen.removePreference(this.findPreference("needsDonate")); } rootView = CommonUI.setBackground(rootView, R.id.prefbackground); return rootView; } @SuppressLint("DefaultLocale") private Uri save(String fromPath) { if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { Toast.makeText(getActivity(), "Access to SD denied", Toast.LENGTH_LONG).show(); return null; } String filename = String.format(fromPath.substring(fromPath.lastIndexOf('/') + 1, fromPath.length())); File targetFile = new File(getActivity().getExternalFilesDir(null), filename); targetFile.getParentFile().mkdirs(); try { FileInputStream in = new FileInputStream(new File(fromPath)); FileOutputStream out = new FileOutputStream(targetFile); out.write(new StringBuilder(512).toString().getBytes()); byte[] buffer = new byte[1024]; int len; while ((len = in.read(buffer)) > 0){ out.write(buffer, 0, len); } in.close(); out.close(); } catch (IOException e) { Toast.makeText(getActivity(), "Failed to copy file to SD \n" + e.getMessage(), Toast.LENGTH_LONG).show(); return null; } return Uri.fromFile(targetFile); } }