diff --git a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java index b9d526b5..f3963fff 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java +++ b/app/src/main/java/com/emanuelef/remote_capture/CaptureService.java @@ -39,7 +39,6 @@ import android.net.NetworkRequest; import android.net.Uri; import android.net.VpnService; import android.os.Build; -import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.ParcelFileDescriptor; @@ -54,7 +53,9 @@ import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.core.content.ContextCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; import androidx.preference.PreferenceManager; import com.emanuelef.remote_capture.activities.CaptureCtrl; @@ -148,7 +149,8 @@ public class CaptureService extends VpnService implements Runnable { private String mSocks5Address; private int mSocks5Port; private String mSocks5Auth; - private CaptureStats mLastStats; + private static final MutableLiveData lastStats = new MutableLiveData<>(); + private static final MutableLiveData serviceStatus = new MutableLiveData<>(); private boolean mLowMemory; private BroadcastReceiver mNewAppsInstallReceiver; @@ -168,11 +170,10 @@ public class CaptureService extends VpnService implements Runnable { * After the analysis, requests will be routed to the primary DNS server. */ public static final String VPN_VIRTUAL_DNS_SERVER = "10.215.173.2"; - public static final String ACTION_STATS_DUMP = "stats_dump"; - public static final String ACTION_SERVICE_STATUS = "service_status"; - public static final String SERVICE_STATUS_KEY = "status"; - public static final String SERVICE_STATUS_STARTED = "started"; - public static final String SERVICE_STATUS_STOPPED = "stopped"; + public enum ServiceStatus { + STOPPED, + STARTED + } static { /* Load native library */ @@ -202,7 +203,7 @@ public class CaptureService extends VpnService implements Runnable { private int abortStart() { stopService(); - sendServiceStatus(SERVICE_STATUS_STOPPED); + updateServiceStatus(ServiceStatus.STOPPED); return START_NOT_STICKY; } @@ -1039,7 +1040,7 @@ public class CaptureService extends VpnService implements Runnable { // Notify mHandler.post(() -> { - sendServiceStatus(SERVICE_STATUS_STOPPED); + updateServiceStatus(ServiceStatus.STOPPED); CaptureCtrl.notifyCaptureStopped(this, getStats()); }); } @@ -1273,29 +1274,28 @@ public class CaptureService extends VpnService implements Runnable { } } + // called from native public void sendStatsDump(CaptureStats stats) { //Log.d(TAG, "sendStatsDump"); - mLastStats = stats; - - Bundle bundle = new Bundle(); - bundle.putSerializable("value", stats); - Intent intent = new Intent(ACTION_STATS_DUMP); - intent.putExtras(bundle); last_bytes = stats.bytes_sent + stats.bytes_rcvd; last_connections = stats.tot_conns; mHandler.post(this::updateNotification); - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + // notify the observers + lastStats.postValue(stats); } - // also called from native + // called from native private void sendServiceStatus(String cur_status) { - Intent intent = new Intent(ACTION_SERVICE_STATUS); - intent.putExtra(SERVICE_STATUS_KEY, cur_status); - LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + updateServiceStatus(cur_status.equals("started") ? ServiceStatus.STARTED : ServiceStatus.STOPPED); + } - if(cur_status.equals(SERVICE_STATUS_STARTED)) { + private void updateServiceStatus(ServiceStatus cur_status) { + // notify the observers + serviceStatus.postValue(cur_status); + + if(cur_status == ServiceStatus.STARTED) { if(mMalwareDetectionEnabled) reloadMalwareWhitelist(); reloadBlocklist(); @@ -1391,10 +1391,18 @@ public class CaptureService extends VpnService implements Runnable { } public static @NonNull CaptureStats getStats() { - CaptureStats stats = (INSTANCE != null) ? INSTANCE.mLastStats : null; + CaptureStats stats = lastStats.getValue(); return((stats != null) ? stats : new CaptureStats()); } + public static void observeStats(LifecycleOwner lifecycleOwner, Observer observer) { + lastStats.observe(lifecycleOwner, observer); + } + + public static void observeStatus(LifecycleOwner lifecycleOwner, Observer observer) { + serviceStatus.observe(lifecycleOwner, observer); + } + public static void waitForCaptureStop() { if(INSTANCE == null) return; diff --git a/app/src/main/java/com/emanuelef/remote_capture/MitmReceiver.java b/app/src/main/java/com/emanuelef/remote_capture/MitmReceiver.java index e3d24ca3..6b526196 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/MitmReceiver.java +++ b/app/src/main/java/com/emanuelef/remote_capture/MitmReceiver.java @@ -20,17 +20,16 @@ package com.emanuelef.remote_capture; import android.content.Context; -import android.content.Intent; import android.net.Uri; -import android.os.Handler; -import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.SystemClock; import android.util.Log; import android.util.LruCache; import android.util.SparseArray; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.Observer; import com.emanuelef.remote_capture.interfaces.ConnectionsListener; import com.emanuelef.remote_capture.interfaces.MitmListener; @@ -67,15 +66,14 @@ import java.util.StringTokenizer; public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener { private static final String TAG = "MitmReceiver"; public static final int TLS_DECRYPTION_PROXY_PORT = 7780; - public static final String ACTION_MITM_ADDON_STATUS_CHANGED = "addon_status_changed"; private Thread mThread; private final ConnectionsRegister mReg; private final Context mContext; private final MitmAddon mAddon; private final MitmAPI.MitmConfig mConfig; + private static final MutableLiveData proxyRunning = new MutableLiveData<>(); private ParcelFileDescriptor mSocketFd; private BufferedOutputStream mKeylog; - private boolean mProxyRunning; // Shared state private final LruCache mPortToConnId = new LruCache<>(64); @@ -140,7 +138,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener public boolean start() throws IOException { Log.d(TAG, "starting"); - mProxyRunning = false; + proxyRunning.postValue(false); if(!mAddon.connect(Context.BIND_IMPORTANT)) { Utils.showToastLong(mContext, R.string.mitm_start_failed); @@ -182,7 +180,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener public void run() { if(mSocketFd == null) { Log.d(TAG, "Null socket, abort"); - mProxyRunning = false; + proxyRunning.postValue(false); return; } @@ -237,9 +235,10 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener if(type == MsgType.MASTER_SECRET) logMasterSecret(msg); - else if(type == MsgType.RUNNING) - handleProxyRunning(); - else { + else if(type == MsgType.RUNNING) { + Log.d(TAG, "MITM proxy is running"); + proxyRunning.postValue(true); + } else { ConnectionDescriptor conn = getConnByLocalPort(port); //Log.d(TAG, "MSG." + type.name() + "[" + msg_len + " B]: port=" + port + ", match=" + (conn != null)); @@ -258,7 +257,7 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener mKeylog = null; } - mProxyRunning = false; + proxyRunning.postValue(false); Log.d(TAG, "End receiving data"); } @@ -286,17 +285,6 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener } } - private void handleProxyRunning() { - Log.d(TAG, "MITM proxy is running"); - mProxyRunning = true; - - // Notify the StatusFragment - new Handler(Looper.getMainLooper()).post(() -> { - Intent intent = new Intent(ACTION_MITM_ADDON_STATUS_CHANGED); - LocalBroadcastManager.getInstance(mContext).sendBroadcast(intent); - }); - } - private void handleMessage(ConnectionDescriptor conn, MsgType type, byte[] message, long tstamp) { // NOTE: we are possibly accessing the conn concurrently if((type == MsgType.TLS_ERROR) || (type == MsgType.HTTP_ERROR) || (type == MsgType.TCP_ERROR)) { @@ -376,7 +364,11 @@ public class MitmReceiver implements Runnable, ConnectionsListener, MitmListener } public boolean isProxyRunning() { - return mProxyRunning; + return Boolean.TRUE.equals(proxyRunning.getValue()); + } + + public static void observeRunning(LifecycleOwner lifecycleOwner, Observer observer) { + proxyRunning.observe(lifecycleOwner, observer); } @Override diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java index 3d4d0cbd..b2e034ca 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/MainActivity.java @@ -21,10 +21,7 @@ package com.emanuelef.remote_capture.activities; import android.Manifest; import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.UriPermission; import android.content.pm.PackageInfo; @@ -46,7 +43,6 @@ import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.adapter.FragmentStateAdapter; @@ -87,7 +83,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; -import java.io.Serializable; import java.util.HashSet; public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener { @@ -97,7 +92,6 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig private AppStateListener mListener; private Uri mPcapUri; private File mKeylogFile; - private BroadcastReceiver mReceiver; private String mPcapFname; private DrawerLayout mDrawer; private SharedPreferences mPrefs; @@ -170,54 +164,40 @@ public class MainActivity extends BaseActivity implements NavigationView.OnNavig setupTabs(); /* Register for service status */ - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String status = intent.getStringExtra(CaptureService.SERVICE_STATUS_KEY); + CaptureService.observeStatus(this, serviceStatus -> { + Log.d(TAG, "Service status: " + serviceStatus.name()); - if (status != null) { - Log.d(TAG, "Service status: " + status); + if (serviceStatus == CaptureService.ServiceStatus.STARTED) + appStateRunning(); + else /* STOPPED */ { + // The service may still be active (on premature native termination) + if (CaptureService.isServiceActive()) + CaptureService.stopService(); - if (status.equals(CaptureService.SERVICE_STATUS_STARTED)) - appStateRunning(); - else if (status.equals(CaptureService.SERVICE_STATUS_STOPPED)) { - // The service may still be active (on premature native termination) - if (CaptureService.isServiceActive()) - CaptureService.stopService(); + mKeylogFile = MitmReceiver.getKeylogFilePath(MainActivity.this); + if(!mKeylogFile.exists() || !CaptureService.isDecryptingTLS()) + mKeylogFile = null; - mKeylogFile = MitmReceiver.getKeylogFilePath(MainActivity.this); - if(!mKeylogFile.exists() || !CaptureService.isDecryptingTLS()) - mKeylogFile = null; + Log.d(TAG, "sslkeylog? " + (mKeylogFile != null)); - Log.d(TAG, "sslkeylog? " + (mKeylogFile != null)); + if((mPcapUri != null) && (Prefs.getDumpMode(mPrefs) == Prefs.DumpMode.PCAP_FILE)) { + showPcapActionDialog(mPcapUri); + mPcapUri = null; + mPcapFname = null; - if((mPcapUri != null) && (Prefs.getDumpMode(mPrefs) == Prefs.DumpMode.PCAP_FILE)) { - showPcapActionDialog(mPcapUri); - mPcapUri = null; - mPcapFname = null; + // will export the keylogfile after saving/sharing pcap + } else if(mKeylogFile != null) + startExportSslkeylogfile(); - // will export the keylogfile after saving/sharing pcap - } else if(mKeylogFile != null) - startExportSslkeylogfile(); - - appStateReady(); - } - } + appStateReady(); } - }; - - LocalBroadcastManager.getInstance(this) - .registerReceiver(mReceiver, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS)); + }); } @Override protected void onDestroy() { super.onDestroy(); - if(mReceiver != null) - LocalBroadcastManager.getInstance(this) - .unregisterReceiver(mReceiver); - mCapHelper = null; } diff --git a/app/src/main/java/com/emanuelef/remote_capture/activities/StatsActivity.java b/app/src/main/java/com/emanuelef/remote_capture/activities/StatsActivity.java index 23e37e58..4c595a36 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/activities/StatsActivity.java +++ b/app/src/main/java/com/emanuelef/remote_capture/activities/StatsActivity.java @@ -21,13 +21,9 @@ package com.emanuelef.remote_capture.activities; import androidx.annotation.NonNull; import androidx.core.view.MenuProvider; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import android.app.ActivityManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.graphics.Color; import android.os.Bundle; import android.view.Menu; @@ -45,7 +41,6 @@ import com.emanuelef.remote_capture.model.CaptureStats; import java.util.Locale; public class StatsActivity extends BaseActivity implements MenuProvider { - private BroadcastReceiver mReceiver; private TextView mBytesSent; private TextView mBytesRcvd; private TextView mPacketsSent; @@ -94,33 +89,13 @@ public class StatsActivity extends BaseActivity implements MenuProvider { } else findViewById(R.id.row_pkts_dropped).setVisibility(View.GONE); - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - updateStats(intent); - } - }; - - /* Register for updates */ - LocalBroadcastManager.getInstance(this) - .registerReceiver(mReceiver, new IntentFilter(CaptureService.ACTION_STATS_DUMP)); + // Listen for stats updates + CaptureService.observeStats(this, this::updateStats); CaptureService.askStatsDump(); } - @Override - protected void onDestroy() { - super.onDestroy(); - - if(mReceiver != null) - LocalBroadcastManager.getInstance(this) - .unregisterReceiver(mReceiver); - } - - private void updateStats(Intent intent) { - CaptureStats stats = Utils.getSerializableExtra(intent, "value", CaptureStats.class); - assert(stats != null); - + private void updateStats(CaptureStats stats) { mBytesSent.setText(Utils.formatBytes(stats.bytes_sent)); mBytesRcvd.setText(Utils.formatBytes(stats.bytes_rcvd)); mPacketsSent.setText(Utils.formatIntShort(stats.pkts_sent)); diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/AppsFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/AppsFragment.java index 792282e3..6702e064 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/AppsFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/AppsFragment.java @@ -19,10 +19,7 @@ package com.emanuelef.remote_capture.fragments; -import android.content.BroadcastReceiver; -import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -38,7 +35,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.emanuelef.remote_capture.CaptureService; import com.emanuelef.remote_capture.ConnectionsRegister; @@ -59,7 +55,6 @@ public class AppsFragment extends Fragment implements ConnectionsListener { private Handler mHandler; private boolean mRefreshApps; private boolean listenerSet; - private BroadcastReceiver mReceiver; @Override public void onPause() { @@ -107,34 +102,15 @@ public class AppsFragment extends Fragment implements ConnectionsListener { }); /* Register for service status */ - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String status = intent.getStringExtra(CaptureService.SERVICE_STATUS_KEY); - - if(CaptureService.SERVICE_STATUS_STARTED.equals(status)) { - if(listenerSet) { - // register the new connection register - unregisterConnsListener(); - registerConnsListener(); - } + CaptureService.observeStatus(this, serviceStatus -> { + if(serviceStatus == CaptureService.ServiceStatus.STARTED) { + if(listenerSet) { + // register the new connection register + unregisterConnsListener(); + registerConnsListener(); } } - }; - - LocalBroadcastManager.getInstance(requireContext()) - .registerReceiver(mReceiver, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS)); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - if(mReceiver != null) { - LocalBroadcastManager.getInstance(requireContext()) - .unregisterReceiver(mReceiver); - mReceiver = null; - } + }); } @Override diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/BlacklistsFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/BlacklistsFragment.java index a0588bf7..c79c1087 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/BlacklistsFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/BlacklistsFragment.java @@ -19,10 +19,6 @@ package com.emanuelef.remote_capture.fragments; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -40,7 +36,6 @@ import androidx.annotation.Nullable; import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.Lifecycle; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import com.emanuelef.remote_capture.CaptureService; import com.emanuelef.remote_capture.PCAPdroid; @@ -54,7 +49,6 @@ public class BlacklistsFragment extends Fragment implements BlacklistsStateListe private BlacklistsAdapter mAdapter; private Blacklists mBlacklists; private MenuItem mUpdateItem; - private BroadcastReceiver mReceiver; private Handler mHandler; @Override @@ -73,33 +67,19 @@ public class BlacklistsFragment extends Fragment implements BlacklistsStateListe mHandler = new Handler(Looper.getMainLooper()); - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String status = intent.getStringExtra(CaptureService.SERVICE_STATUS_KEY); - - if(status != null) - refreshStatus(); - } - }; + CaptureService.observeStatus(this, serviceStatus -> refreshStatus()); } @Override public void onResume() { super.onResume(); mBlacklists.addOnChangeListener(this); - - LocalBroadcastManager.getInstance(requireContext()) - .registerReceiver(mReceiver, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS)); } @Override public void onPause() { super.onPause(); mBlacklists.removeOnChangeListener(this); - - LocalBroadcastManager.getInstance(requireContext()) - .unregisterReceiver(mReceiver); } @Override diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java index dc0a0f29..1c23b495 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/ConnectionsFragment.java @@ -21,10 +21,8 @@ package com.emanuelef.remote_capture.fragments; import android.app.Activity; import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; import android.net.Uri; import android.os.Bundle; import android.os.Handler; @@ -49,7 +47,6 @@ import androidx.appcompat.widget.SearchView; import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.Lifecycle; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.RecyclerView; @@ -95,7 +92,6 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener private MenuItem mMenuFilter; private MenuItem mMenuItemSearch; private MenuItem mSave; - private BroadcastReceiver mReceiver; private Uri mCsvFname; private AppsResolver mApps; private SearchView mSearchView; @@ -261,41 +257,23 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener mQueryToApply = search; // Register for service status - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String status = intent.getStringExtra(CaptureService.SERVICE_STATUS_KEY); - - if(CaptureService.SERVICE_STATUS_STARTED.equals(status)) { - // register the new connection register - if(listenerSet) { - unregisterConnsListener(); - registerConnsListener(); - } - - autoScroll = true; - showFabDown(false); - mOldConnectionsText.setVisibility(View.GONE); - mEmptyText.setText(R.string.no_connections); - mApps.clear(); + CaptureService.observeStatus(this, serviceStatus -> { + if(serviceStatus == CaptureService.ServiceStatus.STARTED) { + // register the new connection register + if(listenerSet) { + unregisterConnsListener(); + registerConnsListener(); } - refreshMenuIcons(); + autoScroll = true; + showFabDown(false); + mOldConnectionsText.setVisibility(View.GONE); + mEmptyText.setText(R.string.no_connections); + mApps.clear(); } - }; - LocalBroadcastManager.getInstance(requireContext()) - .registerReceiver(mReceiver, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS)); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - if(mReceiver != null) { - LocalBroadcastManager.getInstance(requireContext()) - .unregisterReceiver(mReceiver); - } + refreshMenuIcons(); + }); } @Override @@ -718,7 +696,6 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener return; boolean is_enabled = (CaptureService.getConnsRegister() != null); - Context ctx = requireContext(); mMenuItemSearch.setVisible(is_enabled); // NOTE: setEnabled does not work for this //mMenuFilter.setEnabled(is_enabled); diff --git a/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java b/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java index f082bd44..7f68accf 100644 --- a/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java +++ b/app/src/main/java/com/emanuelef/remote_capture/fragments/StatusFragment.java @@ -21,10 +21,7 @@ package com.emanuelef.remote_capture.fragments; import android.annotation.SuppressLint; import android.app.Dialog; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.SharedPreferences; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -48,7 +45,6 @@ import androidx.appcompat.widget.SwitchCompat; import androidx.core.view.MenuProvider; import androidx.fragment.app.Fragment; import androidx.lifecycle.Lifecycle; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.PreferenceManager; import com.emanuelef.remote_capture.AppsLoader; @@ -84,7 +80,6 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr private View mQuickSettings; private MainActivity mActivity; private SharedPreferences mPrefs; - private BroadcastReceiver mReceiver; private TextView mFilterDescription; private SwitchCompat mAppFilterSwitch; private String mAppFilter; @@ -109,37 +104,6 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr public void onResume() { super.onResume(); refreshStatus(); - - /* Register for stats update */ - mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - - if(action.equals(CaptureService.ACTION_STATS_DUMP)) - processStatsUpdateIntent(intent); - else if(action.equals(MitmReceiver.ACTION_MITM_ADDON_STATUS_CHANGED)) - refreshDecryptionStatus(); - } - }; - - IntentFilter filter = new IntentFilter(); - filter.addAction(CaptureService.ACTION_STATS_DUMP); - filter.addAction(MitmReceiver.ACTION_MITM_ADDON_STATUS_CHANGED); - - LocalBroadcastManager.getInstance(requireContext()) - .registerReceiver(mReceiver, filter); - } - - @Override - public void onPause() { - super.onPause(); - - if(mReceiver != null) { - LocalBroadcastManager.getInstance(requireContext()) - .unregisterReceiver(mReceiver); - mReceiver = null; - } } @Override @@ -205,6 +169,10 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr mActivity.startCapture(); }); + // Register for updates + MitmReceiver.observeRunning(this, running -> refreshDecryptionStatus()); + CaptureService.observeStats(this, this::onStatsUpdate); + // Make URLs clickable mCollectorInfo.setMovementMethod(LinkMovementMethod.getInstance()); @@ -282,10 +250,7 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr recheckFilterWarning(); } - private void processStatsUpdateIntent(Intent intent) { - CaptureStats stats = Utils.getSerializableExtra(intent, "value", CaptureStats.class); - assert(stats != null); - + private void onStatsUpdate(CaptureStats stats) { Log.d("MainReceiver", "Got StatsUpdate: bytes_sent=" + stats.pkts_sent + ", bytes_rcvd=" + stats.bytes_rcvd + ", pkts_sent=" + stats.pkts_sent + ", pkts_rcvd=" + stats.pkts_rcvd); @@ -431,7 +396,7 @@ public class StatusFragment extends Fragment implements AppStateListener, MenuPr dialog.show(); // NOTE: run this after dialog.show - mOpenAppsList = (AppsListView) dialog.findViewById(R.id.apps_list); + mOpenAppsList = dialog.findViewById(R.id.apps_list); mEmptyAppsView = dialog.findViewById(R.id.no_apps); mEmptyAppsView.setText(R.string.loading_apps);