diff --git a/crashreporter/src/main/AndroidManifest.xml b/crashreporter/src/main/AndroidManifest.xml
index 05f763f2..8146fcf8 100644
--- a/crashreporter/src/main/AndroidManifest.xml
+++ b/crashreporter/src/main/AndroidManifest.xml
@@ -1,24 +1,10 @@
-
-
+
-
-
-
-
\ No newline at end of file
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/CrashReporter.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/CrashReporter.java
index 5a1e8fdb..34831ada 100644
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/CrashReporter.java
+++ b/crashreporter/src/main/java/com/balsikandar/crashreporter/CrashReporter.java
@@ -3,7 +3,6 @@ package com.balsikandar.crashreporter;
import android.content.Context;
import android.content.Intent;
-import com.balsikandar.crashreporter.ui.CrashReporterActivity;
import com.balsikandar.crashreporter.utils.CrashReporterNotInitializedException;
import com.balsikandar.crashreporter.utils.CrashReporterExceptionHandler;
import com.balsikandar.crashreporter.utils.CrashUtil;
@@ -61,10 +60,6 @@ public class CrashReporter {
CrashUtil.logException(exception);
}
- public static Intent getLaunchIntent() {
- return new Intent(applicationContext, CrashReporterActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
-
public static void disableNotification() {
isNotificationEnabled = false;
}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/adapter/CrashLogAdapter.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/adapter/CrashLogAdapter.java
deleted file mode 100644
index 8bf7834a..00000000
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/adapter/CrashLogAdapter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.balsikandar.crashreporter.adapter;
-
-import android.content.Context;
-import android.content.Intent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.balsikandar.crashreporter.ui.LogMessageActivity;
-import com.balsikandar.crashreporter.utils.FileUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-
-import de.mm20.launcher2.crashreporter.R;
-
-/**
- * Created by bali on 10/08/17.
- */
-
-public class CrashLogAdapter extends RecyclerView.Adapter {
-
- private Context context;
- private ArrayList crashFileList;
-
- public CrashLogAdapter(Context context, ArrayList allCrashLogs) {
- this.context = context;
- crashFileList = allCrashLogs;
- }
-
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- View view = LayoutInflater.from(context).inflate(R.layout.custom_item, null);
- return new CrashLogViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- ((CrashLogViewHolder) holder).setUpViewHolder(context, crashFileList.get(position));
- }
-
- @Override
- public int getItemCount() {
- return crashFileList.size();
- }
-
-
- public void updateList(ArrayList allCrashLogs) {
- crashFileList = allCrashLogs;
- notifyDataSetChanged();
- }
-
-
- private class CrashLogViewHolder extends RecyclerView.ViewHolder {
- private TextView textViewMsg, messageLogTime;
-
- CrashLogViewHolder(View itemView) {
- super(itemView);
- messageLogTime = itemView.findViewById(R.id.messageLogTime);
- textViewMsg = itemView.findViewById(R.id.textViewMsg);
- }
-
- void setUpViewHolder(final Context context, final File file) {
- final String filePath = file.getAbsolutePath();
- messageLogTime.setText(file.getName().replaceAll("[a-zA-Z_.]", ""));
- textViewMsg.setText(FileUtils.readFirstLineFromFile(new File(filePath)));
-
- textViewMsg.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(context, LogMessageActivity.class);
- intent.putExtra("LogMessage", filePath);
- context.startActivity(intent);
- }
- });
- }
- }
-}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/adapter/MainPagerAdapter.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/adapter/MainPagerAdapter.java
deleted file mode 100644
index bf572d1c..00000000
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/adapter/MainPagerAdapter.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.balsikandar.crashreporter.adapter;
-
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
-
-import com.balsikandar.crashreporter.ui.CrashLogFragment;
-import com.balsikandar.crashreporter.ui.ExceptionLogFragment;
-
-/**
- * Created by bali on 11/08/17.
- */
-
-public class MainPagerAdapter extends FragmentPagerAdapter {
-
- private CrashLogFragment crashLogFragment;
- private ExceptionLogFragment exceptionLogFragment;
- private String[] titles;
-
- public MainPagerAdapter(FragmentManager fm, String[] titles) {
- super(fm);
- this.titles = titles;
- }
-
- @Override
- public Fragment getItem(int position) {
- if (position == 0) {
- return crashLogFragment = new CrashLogFragment();
- } else if (position == 1) {
- return exceptionLogFragment = new ExceptionLogFragment();
- } else {
- return new CrashLogFragment();
- }
- }
-
- @Override
- public int getCount() {
- return 2;
- }
-
- @Override
- public CharSequence getPageTitle(int position) {
- return titles[position];
- }
-
- public void clearLogs() {
- crashLogFragment.clearLog();
- exceptionLogFragment.clearLog();
- }
-}
\ No newline at end of file
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/CrashLogFragment.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/CrashLogFragment.java
deleted file mode 100644
index 9df1a709..00000000
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/CrashLogFragment.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package com.balsikandar.crashreporter.ui;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.balsikandar.crashreporter.CrashReporter;
-import com.balsikandar.crashreporter.adapter.CrashLogAdapter;
-import com.balsikandar.crashreporter.utils.Constants;
-import com.balsikandar.crashreporter.utils.CrashUtil;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-
-import de.mm20.launcher2.crashreporter.R;
-
-/**
- * Created by bali on 11/08/17.
- */
-
-public class CrashLogFragment extends Fragment {
-
- private CrashLogAdapter logAdapter;
-
- private RecyclerView crashRecyclerView;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.crash_log, container, false);
- crashRecyclerView = (RecyclerView) view.findViewById(R.id.crashRecyclerView);
-
- return view;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- loadAdapter(getActivity(), crashRecyclerView);
- }
-
- private void loadAdapter(Context context, RecyclerView crashRecyclerView) {
-
- logAdapter = new CrashLogAdapter(context, getAllCrashes());
- crashRecyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
- crashRecyclerView.setAdapter(logAdapter);
- }
-
- public void clearLog() {
- if (logAdapter != null) {
- logAdapter.updateList(getAllCrashes());
- }
- }
-
-
- private ArrayList getAllCrashes() {
- String directoryPath;
- String crashReportPath = CrashReporter.getCrashReportPath();
-
- if (TextUtils.isEmpty(crashReportPath)) {
- directoryPath = CrashUtil.getDefaultPath();
- } else {
- directoryPath = crashReportPath;
- }
- File directory = new File(directoryPath);
- if (!directory.exists() || !directory.isDirectory()) {
- throw new RuntimeException("The path provided doesn't exists : " + directoryPath);
- }
- ArrayList listOfFiles = new ArrayList<>(Arrays.asList(directory.listFiles()));
- for (Iterator iterator = listOfFiles.iterator(); iterator.hasNext(); ) {
- if (iterator.next().getName().contains(Constants.EXCEPTION_SUFFIX)) {
- iterator.remove();
- }
- }
- Collections.sort(listOfFiles, Collections.reverseOrder());
- return listOfFiles;
- }
-
-}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/CrashReporterActivity.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/CrashReporterActivity.java
deleted file mode 100644
index 9f94c04d..00000000
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/CrashReporterActivity.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package com.balsikandar.crashreporter.ui;
-
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-import androidx.viewpager.widget.ViewPager;
-
-import com.balsikandar.crashreporter.CrashReporter;
-import com.balsikandar.crashreporter.adapter.MainPagerAdapter;
-import com.balsikandar.crashreporter.utils.Constants;
-import com.balsikandar.crashreporter.utils.CrashUtil;
-import com.balsikandar.crashreporter.utils.FileUtils;
-import com.balsikandar.crashreporter.utils.SimplePageChangeListener;
-import com.google.android.material.tabs.TabLayout;
-
-import java.io.File;
-
-import de.mm20.launcher2.crashreporter.R;
-
-public class CrashReporterActivity extends AppCompatActivity {
-
- private MainPagerAdapter mainPagerAdapter;
- private int selectedTabPosition = 0;
-
- //region activity callbacks
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.log_main_menu, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.delete_crash_logs) {
- clearCrashLog();
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getTheme().applyStyle(R.style.DefaultColors, true);
- setContentView(R.layout.crash_reporter_activity);
-
- Toolbar toolbar = findViewById(R.id.toolbar);
- toolbar.setTitle(getString(R.string.crash_reporter));
- toolbar.setSubtitle(getApplicationName());
- setSupportActionBar(toolbar);
-
- ViewPager viewPager = findViewById(R.id.viewpager);
- if (viewPager != null) {
- setupViewPager(viewPager);
- }
-
- TabLayout tabLayout = findViewById(R.id.tabs);
- tabLayout.setupWithViewPager(viewPager);
- }
- //endregion
-
- private void clearCrashLog() {
- new Thread(new Runnable() {
- @Override
- public void run() {
- String crashReportPath = TextUtils.isEmpty(CrashReporter.getCrashReportPath()) ?
- CrashUtil.getDefaultPath() : CrashReporter.getCrashReportPath();
-
- File[] logs = new File(crashReportPath).listFiles();
- for (File file : logs) {
- FileUtils.delete(file);
- }
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- mainPagerAdapter.clearLogs();
- }
- });
- }
- }).start();
- }
-
- private void setupViewPager(ViewPager viewPager) {
- String[] titles = {getString(R.string.crashes), getString(R.string.exceptions)};
- mainPagerAdapter = new MainPagerAdapter(getSupportFragmentManager(), titles);
- viewPager.setAdapter(mainPagerAdapter);
-
- viewPager.addOnPageChangeListener(new SimplePageChangeListener() {
- @Override
- public void onPageSelected(int position) {
- selectedTabPosition = position;
- }
- });
-
- Intent intent = getIntent();
- if (intent != null && !intent.getBooleanExtra(Constants.LANDING, false)) {
- selectedTabPosition = 1;
- }
- viewPager.setCurrentItem(selectedTabPosition);
- }
-
- private String getApplicationName() {
- ApplicationInfo applicationInfo = getApplicationInfo();
- int stringId = applicationInfo.labelRes;
- return stringId == 0 ? applicationInfo.nonLocalizedLabel.toString() : getString(stringId);
- }
-
-}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/ExceptionLogFragment.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/ExceptionLogFragment.java
deleted file mode 100644
index 6fa4c706..00000000
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/ExceptionLogFragment.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package com.balsikandar.crashreporter.ui;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.balsikandar.crashreporter.CrashReporter;
-import com.balsikandar.crashreporter.adapter.CrashLogAdapter;
-import com.balsikandar.crashreporter.utils.Constants;
-import com.balsikandar.crashreporter.utils.CrashUtil;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-
-import de.mm20.launcher2.crashreporter.R;
-
-/**
- * Created by bali on 11/08/17.
- */
-
-public class ExceptionLogFragment extends Fragment {
-
- private CrashLogAdapter logAdapter;
-
- private RecyclerView exceptionRecyclerView;
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.exception_log, container, false);
- exceptionRecyclerView = (RecyclerView) view.findViewById(R.id.exceptionRecyclerView);
-
- return view;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- loadAdapter(getActivity(), exceptionRecyclerView);
- }
-
- private void loadAdapter(Context context, RecyclerView exceptionRecyclerView) {
-
- logAdapter = new CrashLogAdapter(context, getAllExceptions());
- exceptionRecyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
- exceptionRecyclerView.setAdapter(logAdapter);
- }
-
- public void clearLog() {
- if (logAdapter != null) {
- logAdapter.updateList(getAllExceptions());
- }
- }
-
- public ArrayList getAllExceptions() {
- String directoryPath;
- String crashReportPath = CrashReporter.getCrashReportPath();
-
- if (TextUtils.isEmpty(crashReportPath)){
- directoryPath = CrashUtil.getDefaultPath();
- } else{
- directoryPath = crashReportPath;
- }
-
- File directory = new File(directoryPath);
- if (!directory.exists() || !directory.isDirectory()){
- throw new RuntimeException("The path provided doesn't exists : " + directoryPath);
- }
-
- ArrayList listOfFiles = new ArrayList<>(Arrays.asList(directory.listFiles()));
- for (Iterator iterator = listOfFiles.iterator(); iterator.hasNext(); ) {
- if (iterator.next().getName().contains(Constants.CRASH_SUFFIX)) {
- iterator.remove();
- }
- }
- Collections.sort(listOfFiles, Collections.reverseOrder());
- return listOfFiles;
- }
-
-}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/LogMessageActivity.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/LogMessageActivity.java
deleted file mode 100644
index d06fca6b..00000000
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/ui/LogMessageActivity.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package com.balsikandar.crashreporter.ui;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.TextView;
-
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-import androidx.core.content.FileProvider;
-
-import com.balsikandar.crashreporter.utils.AppUtils;
-import com.balsikandar.crashreporter.utils.FileUtils;
-
-import java.io.File;
-
-import de.mm20.launcher2.crashreporter.R;
-
-public class LogMessageActivity extends AppCompatActivity {
-
- private TextView appInfo;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_log_message);
- appInfo = findViewById(R.id.appInfo);
-
- Intent intent = getIntent();
- if (intent != null) {
- String dirPath = intent.getStringExtra("LogMessage");
- File file = new File(dirPath);
- String crashLog = FileUtils.readFromFile(file);
- TextView textView = findViewById(R.id.logMessage);
- textView.setText(crashLog);
- }
-
- Toolbar myToolbar = findViewById(R.id.toolbar);
- myToolbar.setTitle(getString(R.string.crash_reporter));
- setSupportActionBar(myToolbar);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- getAppInfo();
- }
-
- private void getAppInfo() {
- appInfo.setText(AppUtils.getDeviceDetails(this));
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.crash_detail_menu, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- Intent intent = getIntent();
- String filePath = null;
- if (intent != null) {
- filePath = intent.getStringExtra("LogMessage");
- }
-
- if (item.getItemId() == R.id.delete_log) {
- if (FileUtils.delete(filePath)) {
- finish();
- }
- return true;
- } else if (item.getItemId() == R.id.share_crash_log) {
- shareCrashReport(filePath);
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void shareCrashReport(String filePath) {
- Uri uri = FileProvider.getUriForFile(this,
- this.getApplicationContext().getPackageName() + ".fileprovider",
- new File(filePath));
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType("*/*");
- intent.putExtra(Intent.EXTRA_TEXT, appInfo.getText().toString());
- intent.putExtra(Intent.EXTRA_STREAM, uri);
- startActivity(Intent.createChooser(intent, "Share via"));
- }
-}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/AppUtils.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/AppUtils.java
index c304dae1..357f59f0 100644
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/AppUtils.java
+++ b/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/AppUtils.java
@@ -1,8 +1,5 @@
package com.balsikandar.crashreporter.utils;
-import android.Manifest;
-import android.accounts.Account;
-import android.accounts.AccountManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -11,8 +8,6 @@ import android.content.pm.ResolveInfo;
import android.os.Build;
import android.util.Log;
-import androidx.core.app.ActivityCompat;
-
import java.util.TimeZone;
import java.util.UUID;
@@ -40,9 +35,8 @@ public class AppUtils {
public static String getDeviceDetails(Context context) {
- return "Device Information\n"
- + "\nDEVICE.ID : " + getDeviceId(context)
- + "\nAPP.VERSION : " + getAppVersion(context)
+ return "APP.VERSION : " + getAppVersion(context)
+ + "\nAPP.VERSIONCODE : " + getAppVersionCode(context)
+ "\nLAUNCHER.APP : " + getCurrentLauncherApp(context)
+ "\nTIMEZONE : " + timeZone()
+ "\nVERSION.RELEASE : " + Build.VERSION.RELEASE
@@ -61,12 +55,9 @@ public class AppUtils {
+ "\nMANUFACTURER : " + Build.MANUFACTURER
+ "\nMODEL : " + Build.MODEL
+ "\nPRODUCT : " + Build.PRODUCT
- + "\nSERIAL : " + Build.SERIAL
+ "\nTAGS : " + Build.TAGS
+ "\nTIME : " + Build.TIME
- + "\nTYPE : " + Build.TYPE
- + "\nUNKNOWN : " + Build.UNKNOWN
- + "\nUSER : " + Build.USER;
+ + "\nTYPE : " + Build.TYPE;
}
private static String timeZone() {
@@ -94,7 +85,7 @@ public class AppUtils {
return androidId;
}
- private static int getAppVersion(Context context) {
+ private static int getAppVersionCode(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
@@ -103,4 +94,14 @@ public class AppUtils {
throw new RuntimeException("Could not get package name: " + e);
}
}
+
+ private static String getAppVersion(Context context) {
+ try {
+ PackageInfo packageInfo = context.getPackageManager()
+ .getPackageInfo(context.getPackageName(), 0);
+ return packageInfo.versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new RuntimeException("Could not get package name: " + e);
+ }
+ }
}
diff --git a/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/CrashUtil.java b/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/CrashUtil.java
index 32004420..7d9d04f4 100644
--- a/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/CrashUtil.java
+++ b/crashreporter/src/main/java/com/balsikandar/crashreporter/utils/CrashUtil.java
@@ -3,28 +3,30 @@ package com.balsikandar.crashreporter.utils;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
-import androidx.core.app.NotificationCompat;
-import androidx.core.content.ContextCompat;
-
import com.balsikandar.crashreporter.CrashReporter;
-import de.mm20.launcher2.crashreporter.R;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
import java.io.Writer;
+import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
+import de.mm20.launcher2.crashreporter.R;
+
import static android.content.Context.NOTIFICATION_SERVICE;
import static com.balsikandar.crashreporter.utils.Constants.CHANNEL_NOTIFICATION_ID;
@@ -47,7 +49,13 @@ public class CrashUtil {
String filename = getCrashLogTime() + Constants.CRASH_SUFFIX + Constants.FILE_EXTENSION;
writeToFile(crashReportPath, filename, getStackTrace(throwable));
- showNotification(throwable.getLocalizedMessage(), true);
+ //if (crashReportPath.isEmpty()) crashReportPath = getDefaultPath();
+
+ try {
+ showNotification(throwable.getLocalizedMessage(), filename);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
}
public static void logException(final Exception exception) {
@@ -91,7 +99,7 @@ public class CrashUtil {
}
}
- private static void showNotification(String localisedMsg, boolean isCrash) {
+ private static void showNotification(String localisedMsg, String fileName) throws UnsupportedEncodingException {
if (CrashReporter.isNotificationEnabled()) {
Context context = CrashReporter.getContext();
@@ -101,8 +109,11 @@ public class CrashUtil {
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_NOTIFICATION_ID);
builder.setSmallIcon(R.drawable.ic_warning_black_24dp);
- Intent intent = CrashReporter.getLaunchIntent();
- intent.putExtra(Constants.LANDING, isCrash);
+ String filePath = new File(getDefaultPath(), fileName).getAbsolutePath();
+
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName(context.getPackageName(), "de.mm20.launcher2.ui.settings.SettingsActivity"));
+ intent.putExtra("de.mm20.launcher2.settings.ROUTE", "settings/debug/crashreporter/report?fileName=" + URLEncoder.encode(filePath, "utf8"));
intent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
diff --git a/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReport.kt b/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReport.kt
new file mode 100644
index 00000000..a2b46936
--- /dev/null
+++ b/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReport.kt
@@ -0,0 +1,48 @@
+package de.mm20.launcher2.crashreporter
+
+import android.icu.text.SimpleDateFormat
+import android.icu.util.TimeZone
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.io.File
+import java.util.*
+
+class CrashReport(
+ val type: CrashReportType,
+ val time: Date,
+ val summary: String,
+ val stacktrace: String?,
+ val filePath: String
+) {
+ companion object {
+ suspend fun fromFile(file: File, loadStackTrace: Boolean): CrashReport {
+ val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
+ val time = df.parse(file.name.replace("[a-zA-Z_.]", ""))
+ val content = if (loadStackTrace) {
+ withContext(Dispatchers.IO) {
+ file.inputStream().bufferedReader().use {
+ it.readText()
+ }
+ }
+ } else null
+ val summary = content?.substringBefore("\n")
+ ?: withContext(Dispatchers.IO) {
+ file.inputStream().bufferedReader().use {
+ it.readLine()
+ }
+ }
+ return CrashReport(
+ type = if (file.name.endsWith("_crash.txt")) CrashReportType.Crash else CrashReportType.Exception,
+ time = time,
+ summary = summary,
+ stacktrace = content,
+ filePath = file.absolutePath
+ )
+ }
+ }
+}
+
+enum class CrashReportType {
+ Exception,
+ Crash
+}
\ No newline at end of file
diff --git a/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReporter.kt b/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReporter.kt
index 611e8609..2ae26257 100644
--- a/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReporter.kt
+++ b/crashreporter/src/main/java/de/mm20/launcher2/crashreporter/CrashReporter.kt
@@ -1,8 +1,15 @@
package de.mm20.launcher2.crashreporter
+import android.content.Context
import android.content.Intent
import android.util.Log
+import com.balsikandar.crashreporter.CrashReporter
+import com.balsikandar.crashreporter.utils.AppUtils
+import com.balsikandar.crashreporter.utils.CrashUtil
import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.io.File
object CrashReporter {
fun logException(e: Exception) {
@@ -12,7 +19,23 @@ object CrashReporter {
Log.e("MM20", Log.getStackTraceString(e))
}
- fun getLaunchIntent(): Intent {
- return com.balsikandar.crashreporter.CrashReporter.getLaunchIntent()
+ suspend fun getCrashReports(): List {
+ val files = withContext(Dispatchers.IO) {
+ val now = System.currentTimeMillis()
+ val path = CrashReporter.getCrashReportPath()?.takeIf { it.isEmpty() } ?: CrashUtil.getDefaultPath()
+ File(path).listFiles { f ->
+ f.lastModified() > now - 7 * 24 * 60 * 60 * 1000L
+ }?.sortedByDescending { it.lastModified() }
+ }
+ return files?.map { CrashReport.fromFile(it, false) } ?: emptyList()
+ }
+
+ suspend fun getCrashReport(filePath: String): CrashReport {
+ val path = CrashReporter.getCrashReportPath()?.takeIf { it.isEmpty() } ?: CrashUtil.getDefaultPath()
+ return CrashReport.fromFile(File(filePath), true)
+ }
+
+ fun getDeviceInformation(context: Context): String {
+ return AppUtils.getDeviceDetails(context)
}
}
\ No newline at end of file
diff --git a/crashreporter/src/main/res/layout/activity_log_message.xml b/crashreporter/src/main/res/layout/activity_log_message.xml
deleted file mode 100644
index 69a6f8e7..00000000
--- a/crashreporter/src/main/res/layout/activity_log_message.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/crashreporter/src/main/res/layout/crash_log.xml b/crashreporter/src/main/res/layout/crash_log.xml
deleted file mode 100644
index 21025eda..00000000
--- a/crashreporter/src/main/res/layout/crash_log.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
\ No newline at end of file
diff --git a/crashreporter/src/main/res/layout/crash_reporter_activity.xml b/crashreporter/src/main/res/layout/crash_reporter_activity.xml
deleted file mode 100644
index 85be3d33..00000000
--- a/crashreporter/src/main/res/layout/crash_reporter_activity.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/crashreporter/src/main/res/layout/custom_item.xml b/crashreporter/src/main/res/layout/custom_item.xml
deleted file mode 100644
index 110486c3..00000000
--- a/crashreporter/src/main/res/layout/custom_item.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/crashreporter/src/main/res/layout/exception_log.xml b/crashreporter/src/main/res/layout/exception_log.xml
deleted file mode 100644
index 86d642fc..00000000
--- a/crashreporter/src/main/res/layout/exception_log.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/PreferenceScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/PreferenceScreen.kt
index 5963fd31..11ec5af4 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/PreferenceScreen.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/PreferenceScreen.kt
@@ -2,6 +2,7 @@ package de.mm20.launcher2.ui.component.preferences
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
@@ -23,7 +24,8 @@ import de.mm20.launcher2.ui.locals.LocalNavController
fun PreferenceScreen(
title: String,
floatingActionButton: @Composable () -> Unit = {},
- content: LazyListScope.() -> Unit
+ topBarActions: @Composable RowScope.() -> Unit = {},
+ content: LazyListScope.() -> Unit,
) {
val navController = LocalNavController.current
val systemUiController = rememberSystemUiController()
@@ -50,6 +52,7 @@ fun PreferenceScreen(
Icon(imageVector = Icons.Rounded.ArrowBack, contentDescription = "Back")
}
},
+ actions = topBarActions
)
}) {
LazyColumn(
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt
index b1913742..46274ede 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/SettingsActivity.kt
@@ -6,10 +6,7 @@ import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.collectAsState
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.remember
+import androidx.compose.runtime.*
import androidx.navigation.navArgument
import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.composable
@@ -30,6 +27,8 @@ import de.mm20.launcher2.ui.settings.buildinfo.BuildInfoSettingsScreen
import de.mm20.launcher2.ui.settings.calendarwidget.CalendarWidgetSettingsScreen
import de.mm20.launcher2.ui.settings.cards.CardsSettingsScreen
import de.mm20.launcher2.ui.settings.clockwidget.ClockWidgetSettingsScreen
+import de.mm20.launcher2.ui.settings.crashreporter.CrashReportScreen
+import de.mm20.launcher2.ui.settings.crashreporter.CrashReporterScreen
import de.mm20.launcher2.ui.settings.debug.DebugSettingsScreen
import de.mm20.launcher2.ui.settings.easteregg.EasterEggSettingsScreen
import de.mm20.launcher2.ui.settings.filesearch.FileSearchSettingsScreen
@@ -55,6 +54,12 @@ class SettingsActivity : BaseActivity() {
setContent {
val navController = rememberAnimatedNavController()
+
+ LaunchedEffect(intent) {
+ intent.getStringExtra("de.mm20.launcher2.settings.ROUTE")
+ ?.let { navController.navigate(it) }
+ }
+
val cardStyle by remember {
dataStore.data.map { it.cards }.distinctUntilChanged()
}.collectAsState(
@@ -127,6 +132,17 @@ class SettingsActivity : BaseActivity() {
composable("settings/debug") {
DebugSettingsScreen()
}
+ composable("settings/debug/crashreporter") {
+ CrashReporterScreen()
+ }
+ composable("settings/debug/crashreporter/report?fileName={fileName}",
+ arguments = listOf(navArgument("fileName") {
+ nullable = false
+ })
+ ) {
+ val fileName = it.arguments?.getString("fileName")
+ CrashReportScreen(fileName!!)
+ }
composable(
"settings/license?library={libraryName}",
arguments = listOf(navArgument("libraryName") {
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt
new file mode 100644
index 00000000..f3d28597
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreen.kt
@@ -0,0 +1,92 @@
+package de.mm20.launcher2.ui.settings.crashreporter
+
+import androidx.compose.foundation.horizontalScroll
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.BugReport
+import androidx.compose.material.icons.rounded.Share
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.viewmodel.compose.viewModel
+import de.mm20.launcher2.crashreporter.CrashReportType
+import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
+
+@Composable
+fun CrashReportScreen(fileName: String) {
+ val viewModel: CrashReportScreenVM = viewModel()
+ val context = LocalContext.current
+ val crashReport by remember(fileName) { viewModel.getCrashReport(fileName) }.observeAsState()
+ PreferenceScreen(
+ title = when (crashReport?.type) {
+ CrashReportType.Exception -> "Exception"
+ CrashReportType.Crash -> "Crash"
+ null -> ""
+ },
+ topBarActions = {
+ IconButton(onClick = { crashReport?.let { viewModel.shareCrashReport(context, it) } }) {
+ Icon(imageVector = Icons.Rounded.Share, contentDescription = null)
+ }
+ if (crashReport?.type == CrashReportType.Crash) {
+ IconButton(onClick = { crashReport?.let { viewModel.createIssue(context, it) } }) {
+ Icon(imageVector = Icons.Rounded.BugReport, contentDescription = null)
+ }
+ }
+ }
+ ) {
+ item {
+ Surface(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(8.dp),
+ color = if (crashReport?.type == CrashReportType.Crash) {
+ MaterialTheme.colorScheme.errorContainer
+ } else {
+ MaterialTheme.colorScheme.primaryContainer
+ },
+ shape = RoundedCornerShape(8.dp)
+ ) {
+ Box(
+ modifier = Modifier
+ .fillMaxWidth()
+ .horizontalScroll(
+ rememberScrollState()
+ ),
+ ) {
+ crashReport?.stacktrace?.let {
+ Text(
+ text = it,
+ modifier = Modifier.padding(16.dp),
+ style = MaterialTheme.typography.bodySmall
+ )
+ }
+ }
+ }
+ }
+ item {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(12.dp)
+ ) {
+ Text(text = "Device Information", style = MaterialTheme.typography.titleMedium)
+ val deviceInformation = remember { viewModel.getDeviceInformation(context) }
+ Text(
+ text = deviceInformation,
+ style = MaterialTheme.typography.bodySmall,
+ modifier = Modifier.padding(top = 16.dp, bottom = 8.dp)
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt
new file mode 100644
index 00000000..183c3f5a
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReportScreenVM.kt
@@ -0,0 +1,63 @@
+package de.mm20.launcher2.ui.settings.crashreporter
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import androidx.core.content.FileProvider
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.liveData
+import de.mm20.launcher2.crashreporter.CrashReport
+import de.mm20.launcher2.crashreporter.CrashReporter
+import java.io.File
+import java.net.URLEncoder
+
+class CrashReportScreenVM : ViewModel() {
+ fun getCrashReport(fileName: String) = liveData {
+ emit(CrashReporter.getCrashReport(fileName))
+ }
+
+ fun getDeviceInformation(context: Context): String {
+ return CrashReporter.getDeviceInformation(context)
+ }
+
+ fun createIssue(context: Context, crashReport: CrashReport) {
+ val stacktrace = crashReport.stacktrace?.lines()?.let {
+ if (it.size > 15) it.subList(0, 15)
+ .joinToString("\n") + "\n[${it.size - 15} lines truncated]"
+ else it.joinToString("\n")
+ } ?: ""
+ val body =
+ "## Description\n\n" +
+ "*Please provide as many information about the crash as possible (What did you do before the crash happened? Steps to reproduce?)*\n\n" +
+ "## Strack trace\n\n" +
+ "```\n" +
+ "${stacktrace}\n" +
+ "```\n\n" +
+ "## Device info\n" +
+ "${getDeviceInformation(context).replace("\n", "
")}\n"
+ val url = "https://github.com/MM2-0/Kvaesitso/issues/new?labels=crash+report&body=${
+ URLEncoder.encode(
+ body,
+ "utf8"
+ )
+ }"
+ context.startActivity(Intent(Intent.ACTION_VIEW).apply {
+ data = Uri.parse(url)
+ })
+ }
+
+ fun shareCrashReport(context: Context, crashReport: CrashReport) {
+
+ val uri = FileProvider.getUriForFile(
+ context,
+ context.applicationContext.packageName + ".fileprovider",
+ File(crashReport.filePath)
+ )
+ val intent = Intent(Intent.ACTION_SEND)
+ intent.type = "*/*"
+ intent.putExtra(Intent.EXTRA_TEXT, CrashReporter.getDeviceInformation(context))
+ intent.putExtra(Intent.EXTRA_STREAM, uri)
+ context.startActivity(Intent.createChooser(intent, "Share via"))
+ }
+
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt
new file mode 100644
index 00000000..d48ac497
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreen.kt
@@ -0,0 +1,121 @@
+package de.mm20.launcher2.ui.settings.crashreporter
+
+import android.text.format.DateUtils
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.lazy.items
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.Error
+import androidx.compose.material.icons.rounded.ErrorOutline
+import androidx.compose.material.icons.rounded.Warning
+import androidx.compose.material.icons.rounded.WarningAmber
+import androidx.compose.material3.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.lifecycle.viewmodel.compose.viewModel
+import de.mm20.launcher2.crashreporter.CrashReportType
+import de.mm20.launcher2.ui.R
+import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
+import de.mm20.launcher2.ui.locals.LocalNavController
+import java.net.URLEncoder
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun CrashReporterScreen() {
+ val viewModel: CrashReporterScreenVM = viewModel()
+ val navController = LocalNavController.current
+ val reports by viewModel.reports.observeAsState()
+ val showExceptions by viewModel.showExceptions.observeAsState(true)
+ val showCrashes by viewModel.showCrashes.observeAsState(true)
+ PreferenceScreen(title = stringResource(R.string.preference_crash_reporter)) {
+ reports?.let {
+ item {
+ Row(
+ modifier = Modifier.fillMaxWidth().padding(8.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.End
+ ) {
+ IconToggleButton(checked = showExceptions, onCheckedChange = { value ->
+ viewModel.setShowExceptions(value)
+ }) {
+ Icon(
+ imageVector = if (showExceptions) Icons.Rounded.Warning else Icons.Rounded.WarningAmber,
+ contentDescription = null,
+ modifier = Modifier.alpha(if (showExceptions) 1f else 0.5f)
+ )
+ }
+ IconToggleButton(checked = showCrashes, onCheckedChange = { value ->
+ viewModel.setShowCrashes(value)
+ }) {
+ Icon(
+ imageVector = if (showCrashes) Icons.Rounded.Error else Icons.Rounded.ErrorOutline,
+ contentDescription = null,
+ modifier = Modifier.alpha(if (showCrashes) 1f else 0.5f)
+ )
+ }
+ }
+ }
+ items(it) {
+ OutlinedCard(
+ modifier = Modifier
+ .padding(vertical = 4.dp, horizontal = 8.dp)
+ ,
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable {
+ navController?.navigate("settings/debug/crashreporter/report?fileName=${it.filePath}")
+ }
+ .padding(16.dp)
+ ) {
+ Text(
+ text = DateUtils.formatDateTime(
+ LocalContext.current,
+ it.time.time,
+ DateUtils.FORMAT_SHOW_TIME or DateUtils.FORMAT_SHOW_DATE
+ ),
+ style = MaterialTheme.typography.labelMedium,
+ color = MaterialTheme.colorScheme.secondary
+ )
+ Row(
+ modifier = Modifier.padding(vertical = 8.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides if (it.type == CrashReportType.Exception) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error
+ ) {
+ Icon(
+ modifier = Modifier.padding(end = 8.dp),
+ imageVector = if (it.type == CrashReportType.Exception) Icons.Rounded.Warning else Icons.Rounded.Error,
+ contentDescription = null
+ )
+ Text(
+ text = if (it.type == CrashReportType.Exception) "Exception" else "Crash",
+ style = MaterialTheme.typography.titleMedium
+ )
+ }
+ }
+ Text(
+ text = it.summary,
+ style = MaterialTheme.typography.bodySmall,
+ maxLines = 3,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ }
+ }
+ } ?: item {
+ LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
+ }
+ }
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt
new file mode 100644
index 00000000..76f76945
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/crashreporter/CrashReporterScreenVM.kt
@@ -0,0 +1,45 @@
+package de.mm20.launcher2.ui.settings.crashreporter
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.liveData
+import androidx.lifecycle.viewModelScope
+import de.mm20.launcher2.crashreporter.CrashReport
+import de.mm20.launcher2.crashreporter.CrashReportType
+import de.mm20.launcher2.crashreporter.CrashReporter
+import kotlinx.coroutines.launch
+
+class CrashReporterScreenVM: ViewModel() {
+ fun setShowCrashes(showCrashes: Boolean) {
+ this.showCrashes.value = showCrashes
+ updateReports()
+ }
+
+ fun setShowExceptions(showExceptions: Boolean) {
+ this.showExceptions.value = showExceptions
+ updateReports()
+ }
+
+ private fun updateReports() {
+ val exceptions = showExceptions.value == true
+ val crashes = showCrashes.value == true
+ reports.value = _reports?.filter {
+ it.type == CrashReportType.Exception && exceptions ||
+ it.type == CrashReportType.Crash && crashes
+ }
+ }
+
+ val showExceptions = MutableLiveData(true)
+ val showCrashes = MutableLiveData(true)
+
+ val reports = MutableLiveData?>(null)
+ private var _reports: List? = null
+
+ init {
+ viewModelScope.launch {
+ _reports = CrashReporter.getCrashReports()
+ reports.value = _reports
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/debug/DebugSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/debug/DebugSettingsScreen.kt
index d1d81138..65da4443 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/debug/DebugSettingsScreen.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/debug/DebugSettingsScreen.kt
@@ -12,6 +12,7 @@ import de.mm20.launcher2.ktx.tryStartActivity
import de.mm20.launcher2.ui.R
import de.mm20.launcher2.ui.component.preferences.Preference
import de.mm20.launcher2.ui.component.preferences.PreferenceScreen
+import de.mm20.launcher2.ui.locals.LocalNavController
import kotlinx.coroutines.launch
import java.io.File
@@ -19,6 +20,7 @@ import java.io.File
fun DebugSettingsScreen() {
val context = LocalContext.current
val scope = rememberCoroutineScope()
+ val navController = LocalNavController.current
PreferenceScreen(
stringResource(R.string.preference_screen_debug)
) {
@@ -27,7 +29,7 @@ fun DebugSettingsScreen() {
title = stringResource(R.string.preference_crash_reporter),
summary = stringResource(R.string.preference_crash_reporter_summary),
onClick = {
- context.startActivity(CrashReporter.getLaunchIntent())
+ navController?.navigate("settings/debug/crashreporter")
})
Preference(