diff --git a/.gitignore b/.gitignore index b2ee79b..3004ced 100644 --- a/.gitignore +++ b/.gitignore @@ -41,6 +41,7 @@ captures/ # Keystore files *.jks +*.keystore # vim *.swp diff --git a/app/build.gradle b/app/build.gradle index f1f2267..eef58f3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,17 +4,34 @@ android { compileSdkVersion 23 buildToolsVersion "23.0.3" + signingConfigs { + config { + if(project.hasProperty('atgSigningConfigKeyPassword')) { + keyAlias 'AndroidTcpdumpGui' + keyPassword atgSigningConfigKeyPassword + storeFile file('../sign/release-keystore.keystore') + storePassword atgSigningConfigKeyPassword + } + } + } + defaultConfig { applicationId "com.voxlearning.androidtcpdumpgui" - minSdkVersion 11 + minSdkVersion 14 targetSdkVersion 23 versionCode 1 versionName "1.0" } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.config + } + + debug { + signingConfig signingConfigs.config } } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 030443e..60336c6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,10 +4,16 @@ package="com.voxlearning.androidtcpdumpgui"> + + + + + + - \ No newline at end of file + diff --git a/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureFilePath.java b/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureFilePath.java index f006d88..c91222a 100644 --- a/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureFilePath.java +++ b/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureFilePath.java @@ -38,6 +38,7 @@ public class CaptureFilePath { static public final String FileName_Comment = "comment.txt"; static public final String FileName_Apps = "apps.txt"; static public final String FileName_Logs = "logs.txt"; + static public final String FileName_Gps = "gps.txt"; static public final String FileName_TcpdumpOut = "tcpdump.out.txt"; static public final String FileName_Packets = "packets.pcap"; diff --git a/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureManager.java b/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureManager.java index cc8e91c..629f028 100644 --- a/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureManager.java +++ b/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureManager.java @@ -8,7 +8,11 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.location.Location; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; import android.os.Build; +import android.telephony.TelephonyManager; import android.util.Log; import android.widget.Toast; @@ -129,12 +133,12 @@ public void start(Context context, String intf, String expr) { if(!dirRunning.exists()) { Log.e(TAG, "can not mkdir " + dirRunning.getPath()); + Toast.makeText(context, "Can not write to external storage. Broken sdcard or memory?", Toast.LENGTH_LONG).show(); return; } - try { - recordStart(); + recordStart(context); String fnPackets = CaptureFilePath.OutputDirRunningFilePath(CaptureFilePath.FileName_Packets); String fnTcpdumpOut = CaptureFilePath.OutputDirRunningFilePath(CaptureFilePath.FileName_TcpdumpOut); @@ -255,10 +259,44 @@ public void recordAppName(String appName) { recordLog("app: " + appName); } - private void recordStart() { + private void recordStart(Context context) { String fn = CaptureFilePath.OutputDirRunningFilePath(CaptureFilePath.FileName_Start); Io.writeFile(fn, "" + System.currentTimeMillis()); - recordLog("start"); + + StringBuilder sb = new StringBuilder(); + sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("; ") + .append("MODEL=").append(Build.MODEL).append("; ") + .append("SERIAL=").append(Build.SERIAL).append("\n") + ; + sb.append("FINGERPRINT=").append(Build.FINGERPRINT).append("\n"); + sb.append("RadioVersion=").append(Build.getRadioVersion()).append("\n"); + + TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + String tmDevice = "", tmSerial = "", androidId = ""; + try { + tmDevice = tm.getDeviceId(); + }catch (Exception ignored){} + try { + tmSerial = tm.getSimSerialNumber(); + }catch (Exception ignored){} + try{ + androidId = android.provider.Settings.Secure.getString(context.getContentResolver(), android.provider.Settings.Secure.ANDROID_ID); + }catch (Exception ignored){} + + sb.append("DeviceId=").append(tmDevice).append("; ") + .append("AndroidId=").append(androidId).append("; ") + .append("SimSerialNumber=").append(tmSerial).append("\n"); + + + NetworkInfo ni = null; + try { + ConnectivityManager cm = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + ni = cm.getActiveNetworkInfo(); + } + catch (Exception ignored) { } + sb.append("NetworkInfo=").append(ni == null ? "null" : ni.toString()).append("\n"); + + recordLog("start\n" + sb.toString()); } private void recordStop() { @@ -267,18 +305,19 @@ private void recordStop() { recordLog("stop"); } - public void recordComment(String s) { - String fn = CaptureFilePath.OutputDirRunningFilePath(CaptureFilePath.FileName_Comment); - Io.writeFileAppend(fn, nowLogString() + " " + s + "\n"); - recordLog("comment: " + s); - } - public void recordLog(String s) { String fn = CaptureFilePath.OutputDirRunningFilePath(CaptureFilePath.FileName_Logs); Io.writeFileAppend(fn, nowLogString() + " " + s + "\n"); Log.d(TAG, "recordLog: " + s); } + public void recordGps(Location location) { + String fn = CaptureFilePath.OutputDirRunningFilePath(CaptureFilePath.FileName_Gps); + String s = location == null ? "(unknown-location)" : location.toString(); + + Io.writeFileAppend(fn, nowLogString() + " " + s + "\n"); + Log.d(TAG, "recordGps: " + s); + } static public class Stats { public long mStartTime; diff --git a/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureService.java b/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureService.java index f6a788e..b2ec9bb 100644 --- a/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureService.java +++ b/app/src/main/java/com/voxlearning/androidtcpdumpgui/CaptureService.java @@ -1,17 +1,27 @@ package com.voxlearning.androidtcpdumpgui; +import android.Manifest; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.Service; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.SystemClock; +import android.provider.Settings; +import android.support.v4.app.ActivityCompat; +import android.support.v7.app.AlertDialog; import android.util.Log; -public class CaptureService extends Service { +public class CaptureService extends Service implements LocationListener { static private final String TAG = "CaptureService"; @@ -23,6 +33,7 @@ public class CaptureService extends Service { private CaptureManager mCaptureManager; private AlarmManager mAlarmManager; + private LocationManager mLocationManager; static final public int AlarmInterval_RestartService = 30 * 1000; static final public int DelayInterval_PeriodWork = 5 * 1000; @@ -33,21 +44,21 @@ public class CaptureService extends Service { public void onCreate() { mCaptureManager = new CaptureManager(); mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); + gpsStart(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { - if(ServiceAction_CaptureStart.equals(intent.getAction())) { + if (ServiceAction_CaptureStart.equals(intent.getAction())) { Log.d(TAG, "capture start"); periodWork(); - } - else if(ServiceAction_PeriodWork.equals(intent.getAction())) { + } else if (ServiceAction_PeriodWork.equals(intent.getAction())) { Log.d(TAG, "period work"); periodWork(); - } - else if(ServiceAction_CaptureStop.equals(intent.getAction())) { + } else if (ServiceAction_CaptureStop.equals(intent.getAction())) { Log.d(TAG, "capture stop"); stopSelf(); } @@ -65,6 +76,67 @@ public IBinder onBind(Intent intent) { return null; } + + + + private static final long GPS_MIN_DISTANCE_UPDATE = 10; // The minimum distance to change Updates in meters + private static final long GPS_MIN_DURATION_UPDATE = 30 * 1000; // The minimum time between updates in milliseconds + + @Override + public void onLocationChanged(Location location) { + mCaptureManager.recordGps(location); + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + mCaptureManager.recordLog("gps status changed: provider=" + provider + ", status=" + status); + } + + @Override + public void onProviderEnabled(String provider) { + gpsStop(); + gpsStart(); + } + + @Override + public void onProviderDisabled(String provider) { + gpsStop(); + gpsStart(); + } + + public void gpsStart() { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return; + } + + if (mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { + + mCaptureManager.recordLog("gps start with last known location:" + LocationManager.GPS_PROVIDER); + mCaptureManager.recordGps(mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)); + mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_MIN_DURATION_UPDATE, GPS_MIN_DISTANCE_UPDATE, this); + + } else if (mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { + + mCaptureManager.recordLog("gps start with last known location:" + LocationManager.NETWORK_PROVIDER); + mCaptureManager.recordGps(mLocationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER)); + mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, GPS_MIN_DURATION_UPDATE, GPS_MIN_DISTANCE_UPDATE, this); + + } + } + + public void gpsStop() { + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return; + } + + mCaptureManager.recordLog("gps stop"); + mLocationManager.removeUpdates(this); + } + + + + + static public class PeriodWorkHandler extends Handler { private Context mContext; diff --git a/app/src/main/java/com/voxlearning/androidtcpdumpgui/MainActivity.java b/app/src/main/java/com/voxlearning/androidtcpdumpgui/MainActivity.java index 255e986..e2cb83c 100644 --- a/app/src/main/java/com/voxlearning/androidtcpdumpgui/MainActivity.java +++ b/app/src/main/java/com/voxlearning/androidtcpdumpgui/MainActivity.java @@ -1,10 +1,15 @@ package com.voxlearning.androidtcpdumpgui; +import android.Manifest; import android.annotation.SuppressLint; import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.LocationManager; import android.os.Handler; import android.os.Looper; +import android.provider.Settings; +import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; @@ -126,14 +131,18 @@ private void doStart() { startService(intent); mTimerUpdateUi.postDelayed(); + updateUi(); } private void doStop() { String captureName = mCaptureManager.stop(this); + Intent intent = new Intent(this, CaptureService.class); intent.setAction(CaptureService.ServiceAction_CaptureStop); startService(intent); + updateUi(); + if(captureName != null) { ViewActivity.openCapture(this, captureName); } @@ -145,6 +154,8 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + updateTitleWithVersion(); + mHandler = new Handler(Looper.getMainLooper()); mTimerUpdateUi = new TimerUpdateUi(); mCaptureManager = new CaptureManager(); @@ -192,7 +203,6 @@ public void onClick(View v) { else { doStart(); } - updateUi(); } }); @@ -212,7 +222,7 @@ private void updateUi() { else { mButtonStartStop.setText("Start"); - setTitle(R.string.app_name); + updateTitleWithVersion(); File[] files = new File(CaptureFilePath.OutputDir("")).listFiles(); List names = new ArrayList<>(); @@ -242,6 +252,36 @@ protected void onResume() { super.onResume(); updateUi(); mTimerUpdateUi.postDelayed(); + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + new AlertDialog.Builder(this) + .setTitle("Location") + .setMessage("Please allow this app to use GPS & Network Location") + .show(); + } + + + LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); + boolean isGpsLocationEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); + + if(!isGpsLocationEnabled) { + new AlertDialog.Builder(this) + .setTitle("Location").setMessage("GPS is not enabled. Do you want to go to settings menu?") + .setPositiveButton("Settings", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + MainActivity.this.startActivity(intent); + } + }).setNegativeButton("Cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }).show(); + } } + private void updateTitleWithVersion() { + String s = getString(R.string.app_name); + setTitle(s + " (" + BuildConfig.VERSION_NAME + "/" + BuildConfig.VERSION_CODE + ")"); + } } diff --git a/app/src/main/java/com/voxlearning/androidtcpdumpgui/ViewActivity.java b/app/src/main/java/com/voxlearning/androidtcpdumpgui/ViewActivity.java index 5689099..b07b2ad 100644 --- a/app/src/main/java/com/voxlearning/androidtcpdumpgui/ViewActivity.java +++ b/app/src/main/java/com/voxlearning/androidtcpdumpgui/ViewActivity.java @@ -213,6 +213,7 @@ private void doSaveCommentZipShare() { dirCapture + "/" + CaptureFilePath.FileName_Stop, dirCapture + "/" + CaptureFilePath.FileName_Apps, dirCapture + "/" + CaptureFilePath.FileName_Comment, + dirCapture + "/" + CaptureFilePath.FileName_Gps, dirCapture + "/" + CaptureFilePath.FileName_Logs, dirCapture + "/" + CaptureFilePath.FileName_Packets, dirCapture + "/" + CaptureFilePath.FileName_TcpdumpOut, diff --git a/build.sh b/build.sh index b6ae15e..2f56b22 100755 --- a/build.sh +++ b/build.sh @@ -18,7 +18,9 @@ fi echo "Assembling AndroidTcpdumpGui ..." if gradle :app:assembleRelease; then - cp app/build/outputs/apk/app-release-unsigned.apk ./AndroidTcpdumpGui.apk + if [ -f app/build/outputs/apk/app-release.apk ]; then + cp app/build/outputs/apk/app-release.apk ./AndroidTcpdumpGui.apk + fi echo "Done" else echo "Error" diff --git a/app/tcpdump.txt b/doc/tcpdump.txt similarity index 100% rename from app/tcpdump.txt rename to doc/tcpdump.txt