Decouple fragments from MainActivity

This commit is contained in:
emanuele-f 2021-02-27 17:44:23 +01:00
parent 62b4c9e1d8
commit 995f3cdfef
6 changed files with 94 additions and 115 deletions

View File

@ -51,10 +51,10 @@ import android.widget.TextView;
import com.emanuelef.remote_capture.AppsLoader;
import com.emanuelef.remote_capture.ConnectionsRegister;
import com.emanuelef.remote_capture.fragments.AppsFragment;
import com.emanuelef.remote_capture.interfaces.AppStateListener;
import com.emanuelef.remote_capture.interfaces.AppsLoadListener;
import com.emanuelef.remote_capture.model.AppDescriptor;
import com.emanuelef.remote_capture.model.AppState;
import com.emanuelef.remote_capture.interfaces.AppStateListener;
import com.emanuelef.remote_capture.views.AppsListView;
import com.emanuelef.remote_capture.CaptureService;
import com.emanuelef.remote_capture.fragments.ConnectionsFragment;
@ -88,7 +88,7 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener
AppState mState;
ViewPager2 viewPager2;
TabLayout tabLayout;
List<AppStateListener> mStateListeners;
AppStateListener mListener;
AppsListView.OnSelectedAppListener mTmpAppFilterListener;
AppDescriptor mNoFilterApp;
@ -145,9 +145,6 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener
}
mOpenAppsWhenDone = false;
mInstalledApps = null;
mTmpAppFilterListener = null;
mStateListeners = new ArrayList<>();
CaocConfig.Builder.create()
.errorDrawable(R.drawable.ic_app_crash)
@ -256,9 +253,13 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener
openAppSelector();
}
public void setAppStateListener(AppStateListener listener) {
mListener = listener;
}
private void notifyAppState() {
for(AppStateListener listener: mStateListeners)
listener.appStateChanged(mState);
if(mListener != null)
mListener.appStateChanged(mState);
}
public void appStateReady() {
@ -454,14 +455,6 @@ public class MainActivity extends AppCompatActivity implements AppsLoadListener
}
}
public void addAppStateListener(AppStateListener listener) {
mStateListeners.add(listener);
}
public void removeAppStateListener(AppStateListener listener) {
mStateListeners.remove(listener);
}
public AppState getState() {
return(mState);
}

View File

@ -33,7 +33,6 @@ import androidx.recyclerview.widget.RecyclerView;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.Utils;
import com.emanuelef.remote_capture.activities.MainActivity;
import com.emanuelef.remote_capture.model.AppDescriptor;
import com.emanuelef.remote_capture.model.AppStats;
@ -45,7 +44,7 @@ import java.util.Objects;
public class AppsStatsAdapter extends RecyclerView.Adapter<AppsStatsAdapter.ViewHolder> {
private static final String TAG = "ConnectionsAdapter";
private final MainActivity mActivity;
private final Context mContext;
private final LayoutInflater mLayoutInflater;
private final Drawable mUnknownIcon;
private View.OnClickListener mListener;
@ -65,7 +64,7 @@ public class AppsStatsAdapter extends RecyclerView.Adapter<AppsStatsAdapter.View
traffic = itemView.findViewById(R.id.traffic);
}
public void bindAppStats(MainActivity activity, AppStats stats, Map<Integer, AppDescriptor> apps, Drawable unknownIcon) {
public void bindAppStats(Context context, AppStats stats, Map<Integer, AppDescriptor> apps, Drawable unknownIcon) {
Drawable appIcon;
// NOTE: can be null
@ -77,7 +76,7 @@ public class AppsStatsAdapter extends RecyclerView.Adapter<AppsStatsAdapter.View
String info_txt = (app != null) ? app.getName() : Integer.toString(stats.getUid());
if(stats.num_connections > 1)
info_txt += " (" + Utils.formatNumber(activity, stats.num_connections) + ")";
info_txt += " (" + Utils.formatNumber(context, stats.num_connections) + ")";
info.setText(info_txt);
@ -85,10 +84,10 @@ public class AppsStatsAdapter extends RecyclerView.Adapter<AppsStatsAdapter.View
}
}
public AppsStatsAdapter(MainActivity context) {
mActivity = context;
mLayoutInflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mUnknownIcon = ContextCompat.getDrawable(mActivity, android.R.drawable.ic_menu_help);
public AppsStatsAdapter(Context context) {
mContext = context;
mLayoutInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mUnknownIcon = ContextCompat.getDrawable(mContext, android.R.drawable.ic_menu_help);
mListener = null;
mStats = new ArrayList<>();
}
@ -116,7 +115,7 @@ public class AppsStatsAdapter extends RecyclerView.Adapter<AppsStatsAdapter.View
if(stats == null)
return;
holder.bindAppStats(mActivity, stats, mApps, mUnknownIcon);
holder.bindAppStats(mContext, stats, mApps, mUnknownIcon);
}
@Override

View File

@ -37,19 +37,18 @@ import com.emanuelef.remote_capture.model.ConnectionDescriptor;
import com.emanuelef.remote_capture.ConnectionsRegister;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.Utils;
import com.emanuelef.remote_capture.activities.MainActivity;
import java.util.Map;
import java.util.Objects;
public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.ViewHolder> {
private static final String TAG = "ConnectionsAdapter";
private final MainActivity mActivity;
private final LayoutInflater mLayoutInflater;
private final Drawable mUnknownIcon;
private int mItemCount;
private View.OnClickListener mListener;
private Map<Integer, AppDescriptor> mApps;
private final Context mContext;
int mUidFilter;
public static class ViewHolder extends RecyclerView.ViewHolder {
@ -69,7 +68,7 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
statusInd = itemView.findViewById(R.id.status_ind);
}
public void bindConn(MainActivity activity, ConnectionDescriptor conn, Map<Integer, AppDescriptor> apps, Drawable unknownIcon) {
public void bindConn(Context context, ConnectionDescriptor conn, Map<Integer, AppDescriptor> apps, Drawable unknownIcon) {
AppDescriptor app = (apps != null) ? apps.get(conn.uid) : null;
Drawable appIcon;
@ -79,7 +78,7 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
if(conn.info.length() > 0)
remote.setText(conn.info);
else
remote.setText(String.format(activity.getResources().getString(R.string.ip_and_port),
remote.setText(String.format(context.getResources().getString(R.string.ip_and_port),
conn.dst_ip, conn.dst_port));
l7proto.setText(conn.l7proto);
@ -92,10 +91,10 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
}
}
public ConnectionsAdapter(MainActivity context) {
mActivity = context;
mLayoutInflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mUnknownIcon = ContextCompat.getDrawable(mActivity, android.R.drawable.ic_menu_help);
public ConnectionsAdapter(Context context) {
mContext = context;
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mUnknownIcon = ContextCompat.getDrawable(context, android.R.drawable.ic_menu_help);
mListener = null;
mItemCount = 0;
mUidFilter = -1;
@ -128,7 +127,7 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
if(conn == null)
return;
holder.bindConn(mActivity, conn, mApps, mUnknownIcon);
holder.bindConn(mContext, conn, mApps, mUnknownIcon);
}
@Override

View File

@ -1,6 +1,9 @@
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;
@ -11,50 +14,38 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.emanuelef.remote_capture.AppsLoader;
import com.emanuelef.remote_capture.CaptureService;
import com.emanuelef.remote_capture.ConnectionsRegister;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.activities.MainActivity;
import com.emanuelef.remote_capture.adapters.AppsStatsAdapter;
import com.emanuelef.remote_capture.interfaces.AppStateListener;
import com.emanuelef.remote_capture.interfaces.AppsLoadListener;
import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
import com.emanuelef.remote_capture.model.AppDescriptor;
import com.emanuelef.remote_capture.model.AppState;
import com.emanuelef.remote_capture.model.AppStats;
import com.emanuelef.remote_capture.views.EmptyRecyclerView;
import java.util.Map;
public class AppsFragment extends Fragment implements AppStateListener, ConnectionsListener, AppsLoadListener {
public class AppsFragment extends Fragment implements ConnectionsListener, AppsLoadListener {
private EmptyRecyclerView mRecyclerView;
private AppsStatsAdapter mAdapter;
private static final String TAG = "AppsFragment";
private MainActivity mActivity;
private Handler mHandler;
private boolean mRefreshApps;
private boolean listenerSet;
private Map<Integer, AppDescriptor> mApps;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
mActivity = (MainActivity) context;
}
@Override
public void onDestroy() {
super.onDestroy();
mActivity.removeAppStateListener(this);
unregisterListener();
mActivity = null;
unregisterConnsListener();
}
@Override
@ -66,22 +57,19 @@ public class AppsFragment extends Fragment implements AppStateListener, Connecti
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
mRecyclerView = view.findViewById(R.id.apps_stats_view);
LinearLayoutManager layoutMan = new LinearLayoutManager(mActivity);
LinearLayoutManager layoutMan = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(layoutMan);
TextView emptyText = view.findViewById(R.id.no_apps);
mRecyclerView.setEmptyView(emptyText);
mAdapter = new AppsStatsAdapter(mActivity);
mAdapter = new AppsStatsAdapter(getContext());
mRecyclerView.setAdapter(mAdapter);
mHandler = new Handler(Looper.getMainLooper());
mRefreshApps = false;
mAdapter.setClickListener(v -> {
if(!mActivity.canApplyTmpFilter())
return;
int pos = mRecyclerView.getChildLayoutPosition(v);
AppStats item = mAdapter.getItem(pos);
@ -89,21 +77,37 @@ public class AppsFragment extends Fragment implements AppStateListener, Connecti
AppDescriptor app = mApps.get(item.getUid());
if(app != null) {
mActivity.setSelectedApp(app);
mActivity.setActivePage(MainActivity.POS_CONNECTIONS);
// TODO
//mActivity.setSelectedApp(app);
//mActivity.setActivePage(MainActivity.POS_CONNECTIONS);
}
}
});
registerListener();
mActivity.addAppStateListener(this);
registerConnsListener();
(new AppsLoader(mActivity))
(new AppsLoader((AppCompatActivity) getActivity()))
.setAppsLoadListener(this)
.loadAllApps();
LocalBroadcastManager bcast_man = LocalBroadcastManager.getInstance(getContext());
/* Register for service status */
bcast_man.registerReceiver(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
unregisterConnsListener();
registerConnsListener();
}
}
}, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS));
}
private void registerListener() {
private void registerConnsListener() {
if (!listenerSet) {
ConnectionsRegister reg = CaptureService.getConnsRegister();
@ -114,7 +118,7 @@ public class AppsFragment extends Fragment implements AppStateListener, Connecti
}
}
private void unregisterListener() {
private void unregisterConnsListener() {
if(listenerSet) {
ConnectionsRegister reg = CaptureService.getConnsRegister();
if (reg != null)
@ -124,14 +128,6 @@ public class AppsFragment extends Fragment implements AppStateListener, Connecti
}
}
@Override
public void appStateChanged(AppState state) {
if(state == AppState.running) {
unregisterListener();
registerListener();
}
}
// NOTE: do not use synchronized as it could cause a deadlock with the ConnectionsRegister lock
private void doRefreshApps() {
mRefreshApps = false;

View File

@ -19,8 +19,10 @@
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;
@ -32,31 +34,28 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.emanuelef.remote_capture.AppsLoader;
import com.emanuelef.remote_capture.interfaces.AppsLoadListener;
import com.emanuelef.remote_capture.model.AppDescriptor;
import com.emanuelef.remote_capture.model.AppState;
import com.emanuelef.remote_capture.CaptureService;
import com.emanuelef.remote_capture.model.ConnectionDescriptor;
import com.emanuelef.remote_capture.activities.ConnectionDetailsActivity;
import com.emanuelef.remote_capture.adapters.ConnectionsAdapter;
import com.emanuelef.remote_capture.ConnectionsRegister;
import com.emanuelef.remote_capture.views.AppsListView;
import com.emanuelef.remote_capture.views.EmptyRecyclerView;
import com.emanuelef.remote_capture.R;
import com.emanuelef.remote_capture.activities.MainActivity;
import com.emanuelef.remote_capture.interfaces.AppStateListener;
import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
import java.util.Map;
public class ConnectionsFragment extends Fragment implements AppStateListener, ConnectionsListener, AppsListView.OnSelectedAppListener, AppsLoadListener {
public class ConnectionsFragment extends Fragment implements ConnectionsListener, AppsLoadListener {
private static final String TAG = "ConnectionsFragment";
private MainActivity mActivity;
private Handler mHandler;
private ConnectionsAdapter mAdapter;
private View mFabDown;
@ -65,22 +64,11 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
private boolean listenerSet;
private Map<Integer, AppDescriptor> mApps;
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
mActivity = (MainActivity) context;
}
@Override
public void onDestroy() {
super.onDestroy();
mActivity.removeAppStateListener(this);
mActivity.setTmpAppFilterListener(null);
unregisterListener();
mActivity = null;
unregisterConnsListener();
}
@Override
@ -89,7 +77,7 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
return inflater.inflate(R.layout.connections, container, false);
}
private void registerListener() {
private void registerConnsListener() {
if (!listenerSet) {
ConnectionsRegister reg = CaptureService.getConnsRegister();
@ -100,7 +88,7 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
}
}
private void unregisterListener() {
private void unregisterConnsListener() {
if(listenerSet) {
ConnectionsRegister reg = CaptureService.getConnsRegister();
if (reg != null)
@ -115,13 +103,13 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
mHandler = new Handler(Looper.getMainLooper());
mFabDown = view.findViewById(R.id.fabDown);
mRecyclerView = view.findViewById(R.id.connections_view);
LinearLayoutManager layoutMan = new LinearLayoutManager(mActivity);
LinearLayoutManager layoutMan = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(layoutMan);
TextView emptyText = view.findViewById(R.id.no_connections);
mRecyclerView.setEmptyView(emptyText);
mAdapter = new ConnectionsAdapter(mActivity);
mAdapter = new ConnectionsAdapter(getContext());
mRecyclerView.setAdapter(mAdapter);
listenerSet = false;
@ -129,8 +117,6 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
layoutMan.getOrientation());
mRecyclerView.addItemDecoration(dividerItemDecoration);*/
onSelectedApp(mActivity.getTmpFilter());
mAdapter.setClickListener(v -> {
int pos = mRecyclerView.getChildLayoutPosition(v);
ConnectionDescriptor item = mAdapter.getItem(pos);
@ -165,14 +151,30 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
}
});
registerListener();
registerConnsListener();
mActivity.addAppStateListener(this);
mActivity.setTmpAppFilterListener(this);
(new AppsLoader(mActivity))
(new AppsLoader((AppCompatActivity) getActivity()))
.setAppsLoadListener(this)
.loadAllApps();
LocalBroadcastManager bcast_man = LocalBroadcastManager.getInstance(getContext());
/* Register for service status */
bcast_man.registerReceiver(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
unregisterConnsListener();
registerConnsListener();
autoScroll = true;
showFabDown(false);
}
}
}, new IntentFilter(CaptureService.ACTION_SERVICE_STATUS));
}
private void recheckScroll() {
@ -215,17 +217,6 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
super.onResume();
}
@Override
public void appStateChanged(AppState state) {
if(state == AppState.running) {
unregisterListener();
registerListener();
autoScroll = true;
showFabDown(false);
}
}
// This performs an unoptimized adapter refresh
private void refreshUidConnections() {
ConnectionsRegister reg = CaptureService.getConnsRegister();
@ -314,18 +305,19 @@ public class ConnectionsFragment extends Fragment implements AppStateListener, C
});
}
@Override
// TODO
/*
public void onSelectedApp(AppDescriptor app) {
int uid = (app != null) ? app.getUid() : -1;
if(mAdapter.getUidFilter() != uid) {
// rather than calling refreshAllTheConnections, its better to let the register to the
// job by properly scheduling the ConnectionsListener callbacks
unregisterListener();
unregisterConnsListener();
mAdapter.setUidFilter(uid);
registerListener();
registerConnsListener();
}
}
}*/
@Override
public void onAppsInfoLoaded(Map<Integer, AppDescriptor> apps) {

View File

@ -66,7 +66,7 @@ public class StatusFragment extends Fragment implements AppStateListener {
@Override
public void onDestroy() {
mActivity.removeAppStateListener(this);
mActivity.setAppStateListener(null);
mActivity = null;
super.onDestroy();
}
@ -125,7 +125,7 @@ public class StatusFragment extends Fragment implements AppStateListener {
}, new IntentFilter(CaptureService.ACTION_TRAFFIC_STATS_UPDATE));
/* Important: call this after all the fields have been initialized */
mActivity.addAppStateListener(this);
mActivity.setAppStateListener(this);
}
private void processStatsUpdateIntent(Intent intent) {