diff --git a/app/src/debug/java/org/schabi/newpipe/DebugApp.java b/app/src/debug/java/org/schabi/newpipe/DebugApp.java index dba4179c2..ba1fd90cc 100644 --- a/app/src/debug/java/org/schabi/newpipe/DebugApp.java +++ b/app/src/debug/java/org/schabi/newpipe/DebugApp.java @@ -1,12 +1,20 @@ package org.schabi.newpipe; import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.support.annotation.NonNull; import android.support.multidex.MultiDex; import com.facebook.stetho.Stetho; +import com.squareup.leakcanary.AndroidHeapDumper; +import com.squareup.leakcanary.DefaultLeakDirectoryProvider; +import com.squareup.leakcanary.HeapDumper; import com.squareup.leakcanary.LeakCanary; +import com.squareup.leakcanary.LeakDirectoryProvider; import com.squareup.leakcanary.RefWatcher; +import java.io.File; import java.util.concurrent.TimeUnit; public class DebugApp extends App { @@ -49,7 +57,31 @@ public class DebugApp extends App { @Override protected RefWatcher installLeakCanary() { return LeakCanary.refWatcher(this) - .watchDelay(5, TimeUnit.SECONDS) + .heapDumper(new ToggleableHeapDumper(this)) + // give each object 10 seconds to be gc'ed, before leak canary gets nosy on it + .watchDelay(10, TimeUnit.SECONDS) .buildAndInstall(); } + + public static class ToggleableHeapDumper implements HeapDumper { + private final HeapDumper dumper; + private final SharedPreferences preferences; + private final String dumpingAllowanceKey; + + ToggleableHeapDumper(@NonNull final Context context) { + LeakDirectoryProvider leakDirectoryProvider = new DefaultLeakDirectoryProvider(context); + this.dumper = new AndroidHeapDumper(context, leakDirectoryProvider); + this.preferences = PreferenceManager.getDefaultSharedPreferences(context); + this.dumpingAllowanceKey = context.getString(R.string.allow_heap_dumping_key); + } + + private boolean isDumpingAllowed() { + return preferences.getBoolean(dumpingAllowanceKey, false); + } + + @Override + public File dumpHeap() { + return isDumpingAllowed() ? dumper.dumpHeap() : HeapDumper.RETRY_LATER; + } + } } diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index e171c7726..b15a38aae 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -5,6 +5,7 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; import android.os.Build; +import android.support.annotation.Nullable; import android.util.Log; import com.nostra13.universalimageloader.cache.memory.impl.LRULimitedMemoryCache; @@ -167,6 +168,7 @@ public class App extends Application { mNotificationManager.createNotificationChannel(mChannel); } + @Nullable public static RefWatcher getRefWatcher(Context context) { final App application = (App) context.getApplicationContext(); return application.refWatcher; diff --git a/app/src/main/java/org/schabi/newpipe/BaseFragment.java b/app/src/main/java/org/schabi/newpipe/BaseFragment.java index 383e0dc4f..d3e4a4b28 100644 --- a/app/src/main/java/org/schabi/newpipe/BaseFragment.java +++ b/app/src/main/java/org/schabi/newpipe/BaseFragment.java @@ -71,8 +71,9 @@ public abstract class BaseFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); + RefWatcher refWatcher = App.getRefWatcher(getActivity()); - refWatcher.watch(this); + if (refWatcher != null) refWatcher.watch(this); } /*////////////////////////////////////////////////////////////////////////// diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 9a1ecd07a..329bd4165 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -211,6 +211,12 @@ public class MainActivity extends AppCompatActivity { } } + private void onHeapDumpToggled(@NonNull MenuItem item) { + final boolean newToggleState = !item.isChecked(); + sharedPreferences.edit().putBoolean(getString(R.string.allow_heap_dumping_key), + newToggleState).apply(); + item.setChecked(newToggleState); + } /*////////////////////////////////////////////////////////////////////////// // Menu //////////////////////////////////////////////////////////////////////////*/ @@ -232,6 +238,10 @@ public class MainActivity extends AppCompatActivity { inflater.inflate(R.menu.main_menu, menu); } + if (DEBUG) { + getMenuInflater().inflate(R.menu.debug_menu, menu); + } + ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(false); @@ -242,6 +252,17 @@ public class MainActivity extends AppCompatActivity { return true; } + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + MenuItem heapDumpToggle = menu.findItem(R.id.action_toggle_heap_dump); + if (heapDumpToggle != null) { + final boolean isToggled = sharedPreferences.getBoolean( + getString(R.string.allow_heap_dumping_key), false); + heapDumpToggle.setChecked(isToggled); + } + return super.onPrepareOptionsMenu(menu); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { if (DEBUG) Log.d(TAG, "onOptionsItemSelected() called with: item = [" + item + "]"); @@ -262,6 +283,9 @@ public class MainActivity extends AppCompatActivity { case R.id.action_history: NavigationHelper.openHistory(this); return true; + case R.id.action_toggle_heap_dump: + onHeapDumpToggled(item); + return true; default: return super.onOptionsItemSelected(item); } diff --git a/app/src/main/res/menu/debug_menu.xml b/app/src/main/res/menu/debug_menu.xml new file mode 100644 index 000000000..448f9cf23 --- /dev/null +++ b/app/src/main/res/menu/debug_menu.xml @@ -0,0 +1,12 @@ + +
\ No newline at end of file diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 372b917e0..5934fdee6 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -83,6 +83,9 @@