mirror of
https://github.com/emanuele-f/PCAPdroid.git
synced 2026-06-16 21:10:57 +08:00
Optimize adapter ops with connections filters
This commit is contained in:
parent
c190caadfd
commit
2983be8ecf
@ -44,6 +44,7 @@ import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.app.NotificationManagerCompat;
|
||||
@ -521,10 +522,18 @@ public class CaptureService extends VpnService implements Runnable {
|
||||
INSTANCE.stop();
|
||||
}
|
||||
|
||||
public static ConnectionsRegister getConnsRegister() {
|
||||
public static @Nullable ConnectionsRegister getConnsRegister() {
|
||||
return((INSTANCE != null) ? INSTANCE.conn_reg : null);
|
||||
}
|
||||
|
||||
public static @NonNull ConnectionsRegister requireConnsRegister() {
|
||||
ConnectionsRegister reg = getConnsRegister();
|
||||
|
||||
assert(reg != null);
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
public static boolean isCapturingAsRoot() {
|
||||
return((INSTANCE != null) &&
|
||||
(INSTANCE.isRootCapture() == 1));
|
||||
|
||||
@ -19,19 +19,16 @@
|
||||
|
||||
package com.emanuelef.remote_capture;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
|
||||
import com.emanuelef.remote_capture.model.AppDescriptor;
|
||||
import com.emanuelef.remote_capture.model.AppStats;
|
||||
import com.emanuelef.remote_capture.model.ConnectionDescriptor;
|
||||
import com.emanuelef.remote_capture.model.ConnectionsMatcher;
|
||||
import com.emanuelef.remote_capture.model.Prefs;
|
||||
import com.google.gson.Gson;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -92,9 +89,11 @@ public class ConnectionsRegister {
|
||||
int in_items = Math.min((mSize - mNumItems), conns.length);
|
||||
int out_items = conns.length - in_items;
|
||||
int insert_pos = mNumItems;
|
||||
ConnectionDescriptor []removedItems = null;
|
||||
|
||||
if(out_items > 0) {
|
||||
int pos = mTail;
|
||||
removedItems = new ConnectionDescriptor[out_items];
|
||||
|
||||
// update the apps stats
|
||||
for(int i=0; i<out_items; i++) {
|
||||
@ -109,6 +108,7 @@ public class ConnectionsRegister {
|
||||
mAppsStats.remove(uid);
|
||||
}
|
||||
|
||||
removedItems[i] = conn;
|
||||
pos = (pos + 1) % mSize;
|
||||
}
|
||||
}
|
||||
@ -135,10 +135,10 @@ public class ConnectionsRegister {
|
||||
|
||||
for(ConnectionsListener listener: mListeners) {
|
||||
if(out_items > 0)
|
||||
listener.connectionsRemoved(0, out_items);
|
||||
listener.connectionsRemoved(0, removedItems);
|
||||
|
||||
if(conns.length > 0)
|
||||
listener.connectionsAdded(insert_pos - out_items, conns.length);
|
||||
listener.connectionsAdded(insert_pos - out_items, conns);
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +219,11 @@ public class ConnectionsRegister {
|
||||
return mUntrackedItems;
|
||||
}
|
||||
|
||||
private synchronized ConnectionDescriptor getConnSimple(int i) {
|
||||
public boolean hasExclusionFilter() {
|
||||
return(mExclusionsEnabled && !mExclusions.isEmpty());
|
||||
}
|
||||
|
||||
public @Nullable ConnectionDescriptor getConn(int i) {
|
||||
if(i >= mNumItems)
|
||||
return null;
|
||||
|
||||
@ -227,44 +231,7 @@ public class ConnectionsRegister {
|
||||
return mItemsRing[pos];
|
||||
}
|
||||
|
||||
private synchronized ConnectionDescriptor getConnWithFilter(int uidFilter, int target_pos) {
|
||||
// pos is relative to the connections matching the provided uid / exclusions
|
||||
int first = firstPos();
|
||||
int virt_pos = 0;
|
||||
|
||||
for(int i = 0; i < mNumItems; i++) {
|
||||
int pos = (first + i) % mSize;
|
||||
ConnectionDescriptor item = mItemsRing[pos];
|
||||
|
||||
if(matches(item, uidFilter)) {
|
||||
if(virt_pos == target_pos)
|
||||
return item;
|
||||
|
||||
virt_pos++;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasExclusionFilter() {
|
||||
return(mExclusionsEnabled && !mExclusions.isEmpty());
|
||||
}
|
||||
|
||||
private boolean matches(ConnectionDescriptor conn, int uidFilter) {
|
||||
return((conn != null)
|
||||
&& ((uidFilter == Utils.UID_NO_FILTER) || (conn.uid == uidFilter))
|
||||
&& (!mExclusionsEnabled || !mExclusions.matches(conn)));
|
||||
}
|
||||
|
||||
public ConnectionDescriptor getConn(int pos, int uidFilter) {
|
||||
if((uidFilter == Utils.UID_NO_FILTER) && !hasExclusionFilter())
|
||||
return getConnSimple(pos);
|
||||
else
|
||||
return getConnWithFilter(uidFilter, pos);
|
||||
}
|
||||
|
||||
public synchronized int getConnPositionByIncrId(int incr_id) {
|
||||
public synchronized int getConnPositionById(int incr_id) {
|
||||
int first = firstPos();
|
||||
|
||||
for(int i = 0; i < mNumItems; i++) {
|
||||
@ -302,66 +269,6 @@ public class ConnectionsRegister {
|
||||
return rv;
|
||||
}
|
||||
|
||||
public synchronized int getFilteredConnCount(int uidFilter) {
|
||||
if(!hasExclusionFilter() && (uidFilter != Utils.UID_NO_FILTER)) {
|
||||
// Optimized
|
||||
AppStats stats = mAppsStats.get(uidFilter);
|
||||
|
||||
if(stats == null)
|
||||
return 0;
|
||||
return stats.num_connections;
|
||||
} else {
|
||||
// TODO optimize
|
||||
int count = 0;
|
||||
|
||||
for(int i = 0; i < mNumItems; i++) {
|
||||
ConnectionDescriptor item = mItemsRing[i];
|
||||
|
||||
if(matches(item, uidFilter))
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized String dumpConnectionsCsv(Context context, int uidFilter) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
AppsResolver resolver = new AppsResolver(context);
|
||||
|
||||
// Header
|
||||
builder.append(context.getString(R.string.connections_csv_fields_v1));
|
||||
builder.append("\n");
|
||||
|
||||
// Contents
|
||||
for(int i=0; i<getConnCount(); i++) {
|
||||
ConnectionDescriptor conn = getConn(i, uidFilter);
|
||||
|
||||
if(conn != null) {
|
||||
AppDescriptor app = resolver.get(conn.uid);
|
||||
|
||||
builder.append(conn.ipproto); builder.append(",");
|
||||
builder.append(conn.src_ip); builder.append(",");
|
||||
builder.append(conn.src_port); builder.append(",");
|
||||
builder.append(conn.dst_ip); builder.append(",");
|
||||
builder.append(conn.dst_port); builder.append(",");
|
||||
builder.append(conn.uid); builder.append(",");
|
||||
builder.append((app != null) ? app.getName() : ""); builder.append(",");
|
||||
builder.append(conn.l7proto); builder.append(",");
|
||||
builder.append(conn.getStatusLabel(context)); builder.append(",");
|
||||
builder.append((conn.info != null) ? conn.info : ""); builder.append(",");
|
||||
builder.append(conn.sent_bytes); builder.append(",");
|
||||
builder.append(conn.rcvd_bytes); builder.append(",");
|
||||
builder.append(conn.sent_pkts); builder.append(",");
|
||||
builder.append(conn.rcvd_pkts); builder.append(",");
|
||||
builder.append(conn.first_seen); builder.append(",");
|
||||
builder.append(conn.last_seen); builder.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public void saveExclusions() {
|
||||
mPrefs.edit()
|
||||
.putString(Prefs.PREF_EXCLUSIONS, mExclusions.toJson())
|
||||
|
||||
@ -150,10 +150,10 @@ public class ConnectionDetailsActivity extends BaseActivity implements Connectio
|
||||
ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
|
||||
if((reg != null) && !mListenerSet) {
|
||||
mConnPos = reg.getConnPositionByIncrId(mConn.incr_id);
|
||||
mConnPos = reg.getConnPositionById(mConn.incr_id);
|
||||
|
||||
if(mConnPos != -1) {
|
||||
ConnectionDescriptor conn = reg.getConn(mConnPos, Utils.UID_NO_FILTER);
|
||||
ConnectionDescriptor conn = reg.getConn(mConnPos);
|
||||
|
||||
if(conn != null) {
|
||||
if(conn.status < ConnectionDescriptor.CONN_STATUS_CLOSED) {
|
||||
@ -238,10 +238,10 @@ public class ConnectionDetailsActivity extends BaseActivity implements Connectio
|
||||
public void connectionsChanges(int num_connetions) {}
|
||||
|
||||
@Override
|
||||
public void connectionsAdded(int start, int count) {}
|
||||
public void connectionsAdded(int start, ConnectionDescriptor []conns) {}
|
||||
|
||||
@Override
|
||||
public void connectionsRemoved(int start, int count) {}
|
||||
public void connectionsRemoved(int start, ConnectionDescriptor []conns) {}
|
||||
|
||||
@Override
|
||||
public void connectionsUpdated(int[] positions) {
|
||||
@ -252,7 +252,7 @@ public class ConnectionDetailsActivity extends BaseActivity implements Connectio
|
||||
|
||||
for(int pos : positions) {
|
||||
if(pos == mConnPos) {
|
||||
ConnectionDescriptor conn = reg.getConn(pos, Utils.UID_NO_FILTER);
|
||||
ConnectionDescriptor conn = reg.getConn(pos);
|
||||
|
||||
// Double check the incr_id
|
||||
if((conn != null) && (conn.incr_id == mConn.incr_id))
|
||||
|
||||
@ -21,6 +21,7 @@ package com.emanuelef.remote_capture.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -31,6 +32,7 @@ import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
|
||||
import com.emanuelef.remote_capture.model.AppDescriptor;
|
||||
import com.emanuelef.remote_capture.CaptureService;
|
||||
import com.emanuelef.remote_capture.AppsResolver;
|
||||
@ -39,18 +41,24 @@ import com.emanuelef.remote_capture.ConnectionsRegister;
|
||||
import com.emanuelef.remote_capture.R;
|
||||
import com.emanuelef.remote_capture.Utils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.ViewHolder> {
|
||||
public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.ViewHolder>
|
||||
implements ConnectionsListener {
|
||||
private static final String TAG = "ConnectionsAdapter";
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final Drawable mUnknownIcon;
|
||||
private int mItemCount;
|
||||
private int mUnfilteredItemsCount;
|
||||
private View.OnClickListener mListener;
|
||||
private final AppsResolver mApps;
|
||||
private final Context mContext;
|
||||
private int mClickedPosition;
|
||||
private int mUidFilter;
|
||||
private int mNumRemovedItems;
|
||||
private final HashMap<Integer, Integer> mIdToFilteredPos;
|
||||
private ArrayList<ConnectionDescriptor> mFilteredConn;
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
ImageView icon;
|
||||
@ -122,18 +130,17 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
|
||||
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mUnknownIcon = ContextCompat.getDrawable(context, R.drawable.ic_image);
|
||||
mListener = null;
|
||||
mItemCount = 0;
|
||||
mFilteredConn = null;
|
||||
mUnfilteredItemsCount = 0;
|
||||
mNumRemovedItems = 0;
|
||||
mIdToFilteredPos = new HashMap<>();
|
||||
mUidFilter = Utils.UID_NO_FILTER;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
public void setItemCount(int count) {
|
||||
mItemCount = count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItemCount;
|
||||
return((mFilteredConn != null) ? mFilteredConn.size() : mUnfilteredItemsCount);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@ -174,13 +181,143 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
|
||||
return ((conn != null) ? conn.incr_id : Utils.UID_UNKNOWN);
|
||||
}
|
||||
|
||||
private boolean matches(ConnectionDescriptor conn, ConnectionsRegister reg) {
|
||||
return((conn != null)
|
||||
&& ((mUidFilter == Utils.UID_NO_FILTER) || (conn.uid == mUidFilter))
|
||||
&& (!reg.mExclusionsEnabled || !reg.mExclusions.matches(conn)));
|
||||
}
|
||||
|
||||
private int getFilteredItemPos(int incrId) {
|
||||
Integer pos = mIdToFilteredPos.get(incrId);
|
||||
|
||||
if(pos == null)
|
||||
return -1;
|
||||
|
||||
return(pos - mNumRemovedItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsChanges(int num_connetions) {
|
||||
mUnfilteredItemsCount = num_connetions;
|
||||
refreshFilteredConnections();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsAdded(int start, ConnectionDescriptor []conns) {
|
||||
mUnfilteredItemsCount += conns.length;
|
||||
|
||||
if(mFilteredConn == null) {
|
||||
notifyItemRangeInserted(start, conns.length);
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionsRegister reg = CaptureService.requireConnsRegister();
|
||||
int numNew = 0;
|
||||
int vpos = mNumRemovedItems + mFilteredConn.size();
|
||||
|
||||
// Assume that connections are only added at the end of the dataset
|
||||
for(ConnectionDescriptor conn : conns) {
|
||||
if(matches(conn, reg)) {
|
||||
mIdToFilteredPos.put(conn.incr_id, vpos++);
|
||||
mFilteredConn.add(conn);
|
||||
numNew++;
|
||||
}
|
||||
}
|
||||
|
||||
if(numNew > 0)
|
||||
notifyItemRangeInserted(mFilteredConn.size() - numNew, numNew);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsRemoved(int start, ConnectionDescriptor []conns) {
|
||||
mUnfilteredItemsCount -= conns.length;
|
||||
|
||||
if(mFilteredConn == null) {
|
||||
notifyItemRangeRemoved(start, conns.length);
|
||||
return;
|
||||
}
|
||||
|
||||
for(ConnectionDescriptor conn: conns) {
|
||||
if(conn == null)
|
||||
continue;
|
||||
|
||||
int vpos = getFilteredItemPos(conn.incr_id);
|
||||
|
||||
if(vpos != -1) {
|
||||
// Assume that connections are only remove from the start of the dataset
|
||||
mFilteredConn.remove(0);
|
||||
mIdToFilteredPos.remove(conn.incr_id);
|
||||
|
||||
mNumRemovedItems++;
|
||||
notifyItemRemoved(vpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsUpdated(int[] positions) {
|
||||
if(mFilteredConn == null) {
|
||||
for(int pos : positions)
|
||||
notifyItemChanged(pos);
|
||||
return;
|
||||
}
|
||||
|
||||
ConnectionsRegister reg = CaptureService.requireConnsRegister();
|
||||
|
||||
for(int pos : positions) {
|
||||
ConnectionDescriptor conn = reg.getConn(pos);
|
||||
|
||||
if(conn != null) {
|
||||
int vpos = getFilteredItemPos(conn.incr_id);
|
||||
|
||||
if(vpos != -1) {
|
||||
Log.d(TAG, "Changed item " + vpos + ", dataset size: " + getItemCount());
|
||||
notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshFilteredConnections() {
|
||||
final ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
|
||||
if(reg == null)
|
||||
return;
|
||||
|
||||
Log.d(TAG, "refreshFilteredConn (" + mUnfilteredItemsCount + ") unfiltered");
|
||||
mIdToFilteredPos.clear();
|
||||
mNumRemovedItems = 0;
|
||||
|
||||
if((mUidFilter != Utils.UID_NO_FILTER) || reg.hasExclusionFilter()) {
|
||||
int vpos = 0;
|
||||
mFilteredConn = new ArrayList<>();
|
||||
|
||||
for(int i=0; i<mUnfilteredItemsCount; i++) {
|
||||
ConnectionDescriptor conn = reg.getConn(i);
|
||||
|
||||
if(matches(conn, reg)) {
|
||||
mFilteredConn.add(conn);
|
||||
mIdToFilteredPos.put(conn.incr_id, vpos++);
|
||||
}
|
||||
}
|
||||
|
||||
Log.d(TAG, "refreshFilteredConn: " + mFilteredConn.size() + " connections matched");
|
||||
} else
|
||||
mFilteredConn = null;
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public ConnectionDescriptor getItem(int pos) {
|
||||
if(mFilteredConn != null)
|
||||
return mFilteredConn.get(pos);
|
||||
|
||||
ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
|
||||
if((pos < 0) || (pos >= getItemCount()) || (reg == null))
|
||||
if((pos < 0) || (pos >= mUnfilteredItemsCount) || (reg == null))
|
||||
return null;
|
||||
|
||||
return reg.getConn(pos, mUidFilter);
|
||||
return reg.getConn(pos);
|
||||
}
|
||||
|
||||
public void setClickListener(View.OnClickListener listener) {
|
||||
@ -198,4 +335,41 @@ public class ConnectionsAdapter extends RecyclerView.Adapter<ConnectionsAdapter.
|
||||
public ConnectionDescriptor getClickedItem() {
|
||||
return getItem(mClickedPosition);
|
||||
}
|
||||
|
||||
public synchronized String dumpConnectionsCsv() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
AppsResolver resolver = new AppsResolver(mContext);
|
||||
|
||||
// Header
|
||||
builder.append(mContext.getString(R.string.connections_csv_fields_v1));
|
||||
builder.append("\n");
|
||||
|
||||
// Contents
|
||||
for(int i=0; i<getItemCount(); i++) {
|
||||
ConnectionDescriptor conn = getItem(i);
|
||||
|
||||
if(conn != null) {
|
||||
AppDescriptor app = resolver.get(conn.uid);
|
||||
|
||||
builder.append(conn.ipproto); builder.append(",");
|
||||
builder.append(conn.src_ip); builder.append(",");
|
||||
builder.append(conn.src_port); builder.append(",");
|
||||
builder.append(conn.dst_ip); builder.append(",");
|
||||
builder.append(conn.dst_port); builder.append(",");
|
||||
builder.append(conn.uid); builder.append(",");
|
||||
builder.append((app != null) ? app.getName() : ""); builder.append(",");
|
||||
builder.append(conn.l7proto); builder.append(",");
|
||||
builder.append(conn.getStatusLabel(mContext)); builder.append(",");
|
||||
builder.append((conn.info != null) ? conn.info : ""); builder.append(",");
|
||||
builder.append(conn.sent_bytes); builder.append(",");
|
||||
builder.append(conn.rcvd_bytes); builder.append(",");
|
||||
builder.append(conn.sent_pkts); builder.append(",");
|
||||
builder.append(conn.rcvd_pkts); builder.append(",");
|
||||
builder.append(conn.first_seen); builder.append(",");
|
||||
builder.append(conn.last_seen); builder.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +44,7 @@ import com.emanuelef.remote_capture.activities.MainActivity;
|
||||
import com.emanuelef.remote_capture.adapters.AppsStatsAdapter;
|
||||
import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
|
||||
import com.emanuelef.remote_capture.model.AppStats;
|
||||
import com.emanuelef.remote_capture.model.ConnectionDescriptor;
|
||||
import com.emanuelef.remote_capture.views.EmptyRecyclerView;
|
||||
|
||||
public class AppsFragment extends Fragment implements ConnectionsListener {
|
||||
@ -181,12 +182,12 @@ public class AppsFragment extends Fragment implements ConnectionsListener {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsAdded(int start, int count) {
|
||||
public void connectionsAdded(int start, ConnectionDescriptor []conns) {
|
||||
refreshAppsAsync();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsRemoved(int start, int count) {
|
||||
public void connectionsRemoved(int start, ConnectionDescriptor []conns) {
|
||||
refreshAppsAsync();
|
||||
}
|
||||
|
||||
|
||||
@ -57,20 +57,20 @@ import androidx.recyclerview.widget.DividerItemDecoration;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.emanuelef.remote_capture.AppsResolver;
|
||||
import com.emanuelef.remote_capture.CaptureService;
|
||||
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 com.emanuelef.remote_capture.adapters.ExclusionsEditAdapter;
|
||||
import com.emanuelef.remote_capture.model.AppDescriptor;
|
||||
import com.emanuelef.remote_capture.CaptureService;
|
||||
import com.emanuelef.remote_capture.model.AppState;
|
||||
import com.emanuelef.remote_capture.AppsResolver;
|
||||
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.model.ConnectionsMatcher;
|
||||
import com.emanuelef.remote_capture.views.EmptyRecyclerView;
|
||||
import com.emanuelef.remote_capture.R;
|
||||
import com.emanuelef.remote_capture.interfaces.ConnectionsListener;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
@ -344,7 +344,6 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
return super.onContextItemSelected(item);
|
||||
|
||||
reg.mExclusionsEnabled = true;
|
||||
refreshExclusionsMenu();
|
||||
refreshFilteredConnections();
|
||||
return true;
|
||||
}
|
||||
@ -391,26 +390,10 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
mOldConnectionsText.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private boolean hasConnectionFilter() {
|
||||
ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
return((mAdapter.getUidFilter() != Utils.UID_NO_FILTER) || ((reg != null) && reg.hasExclusionFilter()));
|
||||
}
|
||||
|
||||
// This performs an unoptimized adapter refresh
|
||||
private void refreshFilteredConnections() {
|
||||
ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
int item_count;
|
||||
int uid = mAdapter.getUidFilter();
|
||||
|
||||
if(reg != null)
|
||||
item_count = reg.getFilteredConnCount(uid);
|
||||
else
|
||||
item_count = mAdapter.getItemCount();
|
||||
|
||||
Log.d(TAG, "New dataset size (uid=" +uid + "): " + item_count);
|
||||
|
||||
mAdapter.setItemCount(item_count);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
mAdapter.refreshFilteredConnections();
|
||||
refreshExclusionsMenu();
|
||||
recheckScroll();
|
||||
}
|
||||
|
||||
@ -420,15 +403,9 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
// in order to avoid desyncs
|
||||
|
||||
mHandler.post(() -> {
|
||||
if(hasConnectionFilter()) {
|
||||
refreshFilteredConnections();
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "New connections size: " + num_connections);
|
||||
|
||||
Log.d(TAG, "New dataset size: " + num_connections);
|
||||
|
||||
mAdapter.setItemCount(num_connections);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
mAdapter.connectionsChanges(num_connections);
|
||||
recheckScroll();
|
||||
|
||||
if(autoScroll)
|
||||
@ -437,22 +414,18 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsAdded(int start, int count) {
|
||||
public void connectionsAdded(int start, ConnectionDescriptor []conns) {
|
||||
mHandler.post(() -> {
|
||||
Log.d(TAG, "Add " + count + " items at " + start);
|
||||
Log.d(TAG, "Added " + conns.length + " connections at " + start);
|
||||
|
||||
if(!hasConnectionFilter()) {
|
||||
mAdapter.setItemCount(mAdapter.getItemCount() + count);
|
||||
mAdapter.notifyItemRangeInserted(start, count);
|
||||
} else
|
||||
refreshFilteredConnections();
|
||||
mAdapter.connectionsAdded(start, conns);
|
||||
|
||||
if(autoScroll)
|
||||
scrollToBottom();
|
||||
|
||||
ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
ConnectionsRegister reg = CaptureService.requireConnsRegister();
|
||||
|
||||
if((reg != null) && (reg.getUntrackedConnCount() > 0)) {
|
||||
if(reg.getUntrackedConnCount() > 0) {
|
||||
String info = String.format(getString(R.string.older_connections_notice), reg.getUntrackedConnCount());
|
||||
mOldConnectionsText.setText(info);
|
||||
|
||||
@ -465,35 +438,16 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsRemoved(int start, int count) {
|
||||
public void connectionsRemoved(int start,ConnectionDescriptor []conns) {
|
||||
mHandler.post(() -> {
|
||||
Log.d(TAG, "Remove " + count + " items at " + start);
|
||||
|
||||
if (!hasConnectionFilter()) {
|
||||
mAdapter.setItemCount(mAdapter.getItemCount() - count);
|
||||
mAdapter.notifyItemRangeRemoved(start, count);
|
||||
} else
|
||||
refreshFilteredConnections();
|
||||
Log.d(TAG, "Remove " + conns.length + " connections at " + start);
|
||||
mAdapter.connectionsRemoved(start, conns);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionsUpdated(int[] positions) {
|
||||
mHandler.post(() -> {
|
||||
if (hasConnectionFilter()) {
|
||||
refreshFilteredConnections();
|
||||
return;
|
||||
}
|
||||
|
||||
int item_count = mAdapter.getItemCount();
|
||||
|
||||
for(int pos : positions) {
|
||||
if(pos < item_count) {
|
||||
Log.d(TAG, "Changed item " + pos + ", dataset size: " + mAdapter.getItemCount());
|
||||
mAdapter.notifyItemChanged(pos);
|
||||
}
|
||||
}
|
||||
});
|
||||
mHandler.post(() -> mAdapter.connectionsUpdated(positions));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -537,10 +491,7 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
reg.mExclusionsEnabled = !reg.mExclusionsEnabled;
|
||||
|
||||
// Delay the refresh to wait for the menu to be closed
|
||||
(new Handler(requireActivity().getMainLooper())).postDelayed(() -> {
|
||||
refreshExclusionsMenu();
|
||||
refreshFilteredConnections();
|
||||
}, 50);
|
||||
(new Handler(requireActivity().getMainLooper())).postDelayed(this::refreshFilteredConnections, 50);
|
||||
|
||||
return true;
|
||||
} else if(id == R.id.delete_exclusions) {
|
||||
@ -644,12 +595,7 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
}
|
||||
|
||||
private void dumpCsv() {
|
||||
ConnectionsRegister reg = CaptureService.getConnsRegister();
|
||||
|
||||
if(reg == null)
|
||||
return;
|
||||
|
||||
String dump = reg.dumpConnectionsCsv(requireContext(), mAdapter.getUidFilter());
|
||||
String dump = mAdapter.dumpConnectionsCsv();
|
||||
|
||||
if(mCsvFname != null) {
|
||||
Log.d(TAG, "Writing CSV file: " + mCsvFname);
|
||||
@ -736,9 +682,7 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
|
||||
builder.setTitle(R.string.edit_exclusions);
|
||||
builder.setView(exclListView);
|
||||
builder.setPositiveButton(R.string.ok, (dialog, which) -> {
|
||||
updateExclusions(adapter);
|
||||
});
|
||||
builder.setPositiveButton(R.string.ok, (dialog, which) -> updateExclusions(adapter));
|
||||
builder.setNeutralButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
|
||||
|
||||
final AlertDialog alert = builder.create();
|
||||
@ -766,10 +710,8 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
}
|
||||
}
|
||||
|
||||
if(changed) {
|
||||
refreshExclusionsMenu();
|
||||
if(changed)
|
||||
refreshFilteredConnections();
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteExclusions() {
|
||||
@ -779,7 +721,6 @@ public class ConnectionsFragment extends Fragment implements ConnectionsListener
|
||||
return;
|
||||
|
||||
reg.mExclusions.clear();
|
||||
refreshExclusionsMenu();
|
||||
refreshFilteredConnections();
|
||||
}
|
||||
|
||||
|
||||
@ -19,9 +19,11 @@
|
||||
|
||||
package com.emanuelef.remote_capture.interfaces;
|
||||
|
||||
import com.emanuelef.remote_capture.model.ConnectionDescriptor;
|
||||
|
||||
public interface ConnectionsListener {
|
||||
void connectionsChanges(int num_connetions);
|
||||
void connectionsAdded(int start, int count);
|
||||
void connectionsRemoved(int start, int count);
|
||||
void connectionsAdded(int start, ConnectionDescriptor []conns);
|
||||
void connectionsRemoved(int start, ConnectionDescriptor []conns);
|
||||
void connectionsUpdated(int[] positions);
|
||||
}
|
||||
|
||||
@ -22,7 +22,8 @@
|
||||
<TextView
|
||||
android:id="@+id/no_connections"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center_horizontal"
|
||||
android:layout_marginTop="40dp"
|
||||
android:textStyle="italic"
|
||||
@ -33,7 +34,8 @@
|
||||
<com.emanuelef.remote_capture.views.EmptyRecyclerView
|
||||
android:id="@+id/connections_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:scrollbars="vertical"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:fillViewport="true" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user