From ef06c055583e5945f62088871a79f0db82f90f10 Mon Sep 17 00:00:00 2001 From: Chumva Date: Mon, 16 Sep 2019 14:42:41 +0300 Subject: [PATCH] Add logcat buffer --- OsmAnd/AndroidManifest.xml | 1 + OsmAnd/res/layout/recyclerview.xml | 1 + OsmAnd/res/values/strings.xml | 1 + .../plus/development/LogcatActivity.java | 234 ++++++++++++++++++ .../SettingsDevelopmentActivity.java | 22 +- 5 files changed, 249 insertions(+), 10 deletions(-) create mode 100644 OsmAnd/src/net/osmand/plus/development/LogcatActivity.java diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 1810b1fbe4..c77d6116e4 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -846,6 +846,7 @@ + diff --git a/OsmAnd/res/layout/recyclerview.xml b/OsmAnd/res/layout/recyclerview.xml index 106f627a95..3c59afdff3 100644 --- a/OsmAnd/res/layout/recyclerview.xml +++ b/OsmAnd/res/layout/recyclerview.xml @@ -1,5 +1,6 @@ + Logcat buffer Application profile changed to \"%s\" Switch profile Configure profile diff --git a/OsmAnd/src/net/osmand/plus/development/LogcatActivity.java b/OsmAnd/src/net/osmand/plus/development/LogcatActivity.java new file mode 100644 index 0000000000..18c790b765 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/development/LogcatActivity.java @@ -0,0 +1,234 @@ +package net.osmand.plus.development; + +import android.graphics.drawable.ColorDrawable; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.ActionBar; +import android.support.v7.widget.DividerItemDecoration; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import net.osmand.AndroidUtils; +import net.osmand.PlatformUtil; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.activities.OsmandActionBarActivity; + +import org.apache.commons.logging.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class LogcatActivity extends OsmandActionBarActivity { + + public static int MAX_BUFFER_LOG = 1000; + + private static final Log log = PlatformUtil.getLog(LogcatActivity.class); + + private LogcatAsyncTask logcatAsyncTask; + private Map logsMap; + private LogcatAdapter adapter; + + @Override + public void onCreate(Bundle savedInstanceState) { + OsmandApplication app = (OsmandApplication) getApplication(); + app.applyTheme(this); + super.onCreate(savedInstanceState); + setContentView(R.layout.recyclerview); + + ActionBar supportActionBar = getSupportActionBar(); + if (supportActionBar != null) { + supportActionBar.setTitle(R.string.logcat_buffer); + supportActionBar.setElevation(5.0f); + } + + logsMap = new LinkedHashMap() { + @Override + protected boolean removeEldestEntry(Entry eldest) { + return size() > MAX_BUFFER_LOG; + } + }; + + adapter = new LogcatAdapter(); + + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + recyclerView.setAdapter(adapter); + + int colorResId = AndroidUtils.resolveAttribute(app, R.attr.divider_color_basic); + if (colorResId != 0) { + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL); + dividerItemDecoration.setDrawable(new ColorDrawable(ContextCompat.getColor(app, colorResId))); + + recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL)); + } + } + + @Override + protected void onResume() { + super.onResume(); + startLogcatAsyncTask(); + } + + @Override + protected void onPause() { + super.onPause(); + stopLogcatAsyncTask(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int itemId = item.getItemId(); + switch (itemId) { + case android.R.id.home: + finish(); + return true; + + } + return false; + } + + private void onNewLogEntry(int index, String logEntry) { + logsMap.put(index, logEntry); + + runOnUiThread(new Runnable() { + @Override + public void run() { + adapter.setLogs(logsMap.values()); + } + }); + } + + public void startLogcatAsyncTask() { + logcatAsyncTask = new LogcatAsyncTask(this, "*:E"); + logcatAsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + public void stopLogcatAsyncTask() { + if (logcatAsyncTask != null && logcatAsyncTask.getStatus() == AsyncTask.Status.RUNNING) { + logcatAsyncTask.cancel(false); + logcatAsyncTask.stopLogging(); + } + } + + private class LogcatAdapter extends RecyclerView.Adapter { + + private List logs = new ArrayList<>(); + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); + View itemView = inflater.inflate(R.layout.bottom_sheet_item_description_long, viewGroup, false); + + return new LogViewHolder(itemView); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) { + if (holder instanceof LogViewHolder) { + LogViewHolder logViewHolder = (LogViewHolder) holder; + String log = getLog(position); + + logViewHolder.logTextView.setText(log); + } + } + + @Override + public int getItemCount() { + return logs.size(); + } + + private String getLog(int position) { + return logs.get(position); + } + + public void setLogs(Collection logs) { + this.logs.clear(); + if (logs != null && !logs.isEmpty()) { + this.logs.addAll(logs); + } + notifyDataSetChanged(); + } + + private class LogViewHolder extends RecyclerView.ViewHolder { + + final TextView logTextView; + + public LogViewHolder(View itemView) { + super(itemView); + this.logTextView = itemView.findViewById(R.id.description); + } + } + } + + public static class LogcatAsyncTask extends AsyncTask { + + private Process processLogcat; + private WeakReference logcatActivity; + private String filterLevel; + private int index = 0; + + LogcatAsyncTask(LogcatActivity logcatActivity, String filterLevel) { + this.logcatActivity = new WeakReference<>(logcatActivity); + this.filterLevel = filterLevel; + } + + @Override + protected Void doInBackground(Void... voids) { + try { + String filter = String.valueOf(android.os.Process.myPid()); + String[] command = {"logcat", filterLevel, " | grep " + filter, "-T", String.valueOf(MAX_BUFFER_LOG)}; + processLogcat = Runtime.getRuntime().exec(command); + + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(processLogcat.getInputStream())); + + String line; + while ((line = bufferedReader.readLine()) != null) { + if (isCancelled()) { + break; + } + publishProgress(line); + } + stopLogging(); + } catch (IOException e) { + // ignore + } catch (Exception e) { + log.error(e); + } + + return null; + } + + @Override + protected void onProgressUpdate(String... values) { + if (values.length > 0 && !isCancelled()) { + LogcatActivity activity = logcatActivity.get(); + if (activity != null) { + activity.onNewLogEntry(index, values[0]); + index++; + } + } + } + + private void stopLogging() { + if (processLogcat != null) { + processLogcat.destroy(); + } + } + } +} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/development/SettingsDevelopmentActivity.java b/OsmAnd/src/net/osmand/plus/development/SettingsDevelopmentActivity.java index 602d1513d3..432fb53164 100644 --- a/OsmAnd/src/net/osmand/plus/development/SettingsDevelopmentActivity.java +++ b/OsmAnd/src/net/osmand/plus/development/SettingsDevelopmentActivity.java @@ -11,25 +11,15 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceCategory; import android.preference.PreferenceScreen; -import android.support.v7.app.AlertDialog; -import android.view.View; -import net.osmand.PlatformUtil; -import net.osmand.StateChangedListener; -import net.osmand.plus.ApplicationMode; import net.osmand.plus.OsmAndLocationSimulation; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.activities.SettingsBaseActivity; -import net.osmand.plus.activities.actions.AppModeDialog; -import net.osmand.plus.profiles.SettingsProfileFragment; import net.osmand.util.SunriseSunset; import java.text.SimpleDateFormat; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; //import net.osmand.plus.development.OsmandDevelopmentPlugin; @@ -139,6 +129,18 @@ public class SettingsDevelopmentActivity extends SettingsBaseActivity { }); cat.addPreference(pref); + pref = new Preference(this); + pref.setTitle(R.string.logcat_buffer); + pref.setKey("logcat_buffer"); + pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + startActivity(new Intent(SettingsDevelopmentActivity.this, LogcatActivity.class)); + return true; + } + }); + cat.addPreference(pref); + PreferenceCategory info = new PreferenceCategory(this); info.setTitle(R.string.info_button); cat.addPreference(info);