Skip to content

Instantly share code, notes, and snippets.

@tanerjn
Created November 9, 2018 18:00
Show Gist options
  • Save tanerjn/26de8eee2ec13e32148d0703842a7e65 to your computer and use it in GitHub Desktop.
Save tanerjn/26de8eee2ec13e32148d0703842a7e65 to your computer and use it in GitHub Desktop.
package connect5g.com.a5geo;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.TelephonyManager;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import static connect5g.com.a5geo.Main.permissionsList;
public class Main extends AppCompatActivity {
/* location and signal strength obtain period(ms), default: every 30 seconds */
int SIGNAL_UPDATE_INTERVAL = 1000*3 ;
/* creating new log file period(ms), default: every 60 minutes */
int LOG_UPDATE_INTERVAL = 1000*60*60 ;
private final static int CHANGE_DISTANCE_INTERVAL= 1000*1;
public final static int PERMISSIONS_REQUEST_LOCATION = 99;
public final static long LOCATION_UPDATE_INTERVAL = 10000;
public final static long LOC_FAST_UPDATE_INTERVAL = 3000;
public final static int PERMISSIONS_REQUEST_MULTIPLE= 123;
public final static int PERMISSIONS_REQUEST_BOTH = 42;
public final static int DEFAULT_TASK_DELAY= 0;
public final static String EXTRA_TO_MAP= "extra_map_msg";
public final static String EXTRA_TO_GPS= "extra_gps_msg";
public final static String NETWORK_UNABLE= "Network not enabled.";
public final static String GPS_UNABLE= "GPS not enabled.";
public final static String REQUEST_DENIED= "Location request denied";
public final static String LOCATION_UPDATE = "LocationService:";
public final static String TAG_LTE_STRENGTH = "getLteSignalStrength";
public final static String TAG_LOCATION_SERVICE = "Location service";
private static String signalLog = "sdcard/signallog.txt";
int OS_VERSION ;
public String signalLogFile, mLog, mLogf, mSignalStrength ;
boolean isEnabledNetwork = false, isEnabledGPS = false, isServiceAllowed, hasNetConnection;
int signalStrength ;
int phoneNetType;
Double latitude, longtitude;
List<CellInfo> cellInfoList;
CellInfoLte cellInfoLte;
CellInfoGsm cellInfoGsm;
CellInfoCdma cellInfoCdma;
CellInfoWcdma cellInfoWcdma;
TextView tvLog;
EditText etSignallingInterval;
EditText etLoggingInterval;
Button btnSendMail;
Button btnClearTv;
Button btnSetIntervals;
Switch swLow, swMedium, swHigh;
protected int mSignallingInterval, mLoggingInterval;
public File SignalLogFile = createFileInstance();
protected LocationManager locationManager;
public Criteria criteria;
public Context mApplicationContext;
public TelephonyManager telephonyManager;
public String networkProvider = LocationManager.NETWORK_PROVIDER;
public String gpsProvider = LocationManager.GPS_PROVIDER;
final static String[] permissionsList = {Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE};
ConnectivityManager connectivityManager;
public NetworkInfo networkInfo;
FusedLocation fusedLocation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.mApplicationContext= getApplicationContext();
Log.v("CREATE:", getTime());
startBackgroundService();
getOS_VERSION();
getUIElements();
if(checkPermission()){
tvLog.setText(buildLog());
}
activateTimers();
activateAppendLog();
activateButtonListeners();
startLocationIntentService();
}
void getUIElements(){
etSignallingInterval = findViewById(R.id.editTextSignallingInterval);
etLoggingInterval = findViewById(R.id.editTextLoggingInterval);
tvLog = findViewById(R.id.textViewLog);
tvLog.setMovementMethod(new ScrollingMovementMethod());
btnSetIntervals = findViewById(R.id.buttonSetIntervals);
btnSendMail = findViewById(R.id.buttonSendMail);
btnClearTv = findViewById(R.id.buttonClearTv);
}
public boolean checkPermission() {
if (ContextCompat.checkSelfPermission(this, permissionsList[0]) == PackageManager.PERMISSION_GRANTED ){
if (ContextCompat.checkSelfPermission(this, permissionsList[1]) == PackageManager.PERMISSION_GRANTED){
if (ContextCompat.checkSelfPermission(this, permissionsList[2]) == PackageManager.PERMISSION_GRANTED) {
isServiceAllowed = true;
}
}
}
else if (ContextCompat.checkSelfPermission(this, permissionsList[0]) == PackageManager.PERMISSION_DENIED ||
ContextCompat.checkSelfPermission(this, permissionsList[2]) == PackageManager.PERMISSION_DENIED){
Toast.makeText(this, "Location share is not permitted, application will not function as supposed to.", Toast.LENGTH_LONG).show();
Log.i(REQUEST_DENIED, "DENIAL OF SERVICE REQUEST.");
isServiceAllowed = false;
}
return isServiceAllowed;
}
/*
RSRP: average power obtained from a single reference, typically ranges between -140db(bad) and -44db(good).
SINR: signal to noise ratio
RSRQ: quality of the received signal, range is between -19.5db(bad) and -3db(good).
GSM: 2G, UMTS: 3G, WCDMA:3G+, CDMA: EVDO, LTE: 4G
CDMA can(does) provide better signals because of the location and the phone characteristics. Also signal strength range varies.
*/
public String getSignalStrength(){
signalStrength = 0;
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
/*PHONE_TYPE_NONE, PHONE_TYPE_GSM, PHONE_TYPE_CDMA, PHONE_TYPE_SIP */
if (telephonyManager!=null) {
phoneNetType = telephonyManager.getPhoneType();
}
if(!checkPermission()){
Log.d(TAG_LTE_STRENGTH, "Permission is not granted");
Toast.makeText(mApplicationContext, "Could not get required permissions", Toast.LENGTH_SHORT).show();
System.exit(1);
}else {
Log.d("phoneNetType", Integer.toString(phoneNetType));
cellInfoList = telephonyManager.getAllCellInfo();
// LTE provides 10 sets of cell information, first 2 is LTE, rests cells are GSM, WCDMA provides 5 cells that are all WCDMA.
// for( CellInfo cellInfo : cellInfoList){
if (!cellInfoList.isEmpty()) {
if (cellInfoList.get(0).getClass() == CellInfoGsm.class) {
Log.i("GSM", "GSM");
cellInfoGsm = (CellInfoGsm) cellInfoList.get(0);
signalStrength = cellInfoGsm.getCellSignalStrength().getDbm();
mSignalStrength = " Signal:" + Integer.toString(signalStrength) + " dB:GSM\n";
}
if (cellInfoList.get(0).getClass() == CellInfoCdma.class) {
Log.i("CDMA", "CDMA");
cellInfoCdma = (CellInfoCdma) cellInfoList.get(0);
signalStrength = cellInfoCdma.getCellSignalStrength().getDbm();
mSignalStrength = " Signal:" + Integer.toString(signalStrength) + " dB:CDMA\n";
}
if (cellInfoList.get(0).getClass() == CellInfoWcdma.class) {
Log.i("WCDMA", "WCDMA");
cellInfoWcdma = (CellInfoWcdma) cellInfoList.get(0);
signalStrength = cellInfoWcdma.getCellSignalStrength().getDbm();
mSignalStrength = " Signal:" + Integer.toString(signalStrength) + " dB:WCDMA\n";
}
if (cellInfoList.get(0).getClass() == CellInfoLte.class) {
Log.i("LTE", "LTE");
cellInfoLte = (CellInfoLte) cellInfoList.get(0);
signalStrength = cellInfoLte.getCellSignalStrength().getDbm();
mSignalStrength = " Signal:" + Integer.toString(signalStrength) + " dB:LTE\n";
}
}
}
// }
return mSignalStrength;
}
public final Location getLocation(){
Location location = null;
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
try{
getApplicationContext().getSystemService(LOCATION_SERVICE);
isEnabledNetwork = locationManager.isProviderEnabled(networkProvider);
isEnabledGPS = locationManager.isProviderEnabled(gpsProvider);
if(!isEnabledNetwork){
Log.d(NETWORK_UNABLE, "Should be enabled for location service.");
}
else if(!isEnabledGPS){
Log.d(GPS_UNABLE, "Should be enabled for location service.");
}
else if( !isServiceAllowed ){
ActivityCompat.requestPermissions(this, permissionsList , PERMISSIONS_REQUEST_MULTIPLE);
if( !checkPermission()){
Toast.makeText(this, "Location share is not permitted, application will not function as supposed to.", Toast.LENGTH_SHORT).show();
Log.i(REQUEST_DENIED, "Denial of location request.");
}
}
else{
if(locationManager != null){
location = locationManager.getLastKnownLocation(networkProvider);
if(location != null)
Log.i(LOCATION_SERVICE, getTime()+"\t location update");
}
}
}catch(Exception err){
err.printStackTrace();
}
return location;
}
LocationListener locationListener = new LocationListener(){
@Override
public void onLocationChanged(Location location) {
if (location != null){
updateLocation(); }
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.i(LOCATION_UPDATE, "Status Changed");
}
@Override
public void onProviderEnabled(String provider) {
Log.i(LOCATION_UPDATE, "Provider Enabled");
}
@Override
public void onProviderDisabled(String provider) {
Log.i(LOCATION_UPDATE, "Provider Disabled");
}
};
/* updates location on a constant interval(default: 30 seconds) */
private Location updateLocation(){
Location location = getLocation();
try{
if(location!=null){
String coordinates = "Lat: "+location.getLatitude()+"\tLon: "+ location.getLongitude();
}else{
Log.d(TAG_LOCATION_SERVICE, "no location update");
Toast.makeText(this, "location is not provided", Toast.LENGTH_SHORT).show();
}
}catch (Exception io){
Toast.makeText(this, "could not update location", Toast.LENGTH_SHORT).show();
Log.d(TAG_LOCATION_SERVICE, "thrown exception");
io.printStackTrace();
}
return location;
}
public String getTime(){
Long epoch = System.currentTimeMillis()/1000;
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy-hh-mm-ss-a");
String fullTime = dateFormat.format(new Date());
return fullTime;
}
void stopLocationListen(){
locationManager.removeUpdates(locationListener);
}
void stopFusedLocationListen(){
if(fusedLocation.fLocationCallback != null ){
fusedLocation.fusedLocationProviderClient.removeLocationUpdates(fusedLocation.fLocationCallback);
}
}
final class Coordinates{
private double latitude = 51.4 ;
private double longtitude = 0.0;
public Coordinates (double latitude, double longtitude){
this.latitude = latitude;
this.longtitude = longtitude;
}
public double getLatitude(){
return latitude;
}public double getLongtitude(){
return longtitude;
}
}
final Coordinates getCoordinates(){
latitude = getLocation().getLatitude();
longtitude = getLocation().getLongitude();
return new Coordinates(latitude, longtitude);
}
private File createFile(String filename, File file){
file = new File(filename);
try {
file.createNewFile();
}catch(Exception ioe){
ioe.printStackTrace();
}
return file;
}
private void insertLog(Context context, File file, String log){
try{
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, true));
bufferedWriter.append(log);
bufferedWriter.newLine();
bufferedWriter.close();
}catch (IOException ioe){
ioe.printStackTrace();
}
}
/* creates log sentence which is shown on the screen. first log is obtained via conventional location services
and second is obtained via fused location services. */
/* uses old location services, GPS/NETWORK provider should be chosen, less efficient than Fused services.
mLog = getTime() + getCoordinates().latitude + getCoordinates().longtitude + getSignalStrength() ;
*/
public String buildLog(){
if( isPlaneModeOn(this)) {
mLogf = getTime() + " AIRPLANE MODE IS ON\n";
} else{
mLogf = getTime() + getFusedCoordinates(getFusedLocationInstance()) + getSignalStrength();
if(!checkNetConnectivity(this)){
// mLogf = getTime() + " NO CELLULAR DATA\n" + mLogf ;
Log.i("SIGNAL:", "NO CELLULAR DATA");
}else{
Log.i("SIGNAL:", "NEW MEASUREMENT");
}
}
return mLogf;
}
String nameFile(){
signalLog = "sdcard/".concat(getTime().concat(".txt"));
return signalLog;
}
public File createFileInstance(){
return new File(nameFile());
}
/* opens the mail client with the actual log file attached. */
protected void sendMail(){
File attachmentFile = new File(Environment.getExternalStorageDirectory(), signalLogFile);
Uri attachmenttUri = FileProvider.getUriForFile(getApplicationContext(), getPackageName()+".fileprovider", attachmentFile);
Intent intentMail = new Intent(android.content.Intent.ACTION_SEND);
intentMail.setType("*/*");
intentMail.putExtra(Intent.EXTRA_SUBJECT, getTime()+ " Signal Log");
intentMail.putExtra(Intent.EXTRA_TEXT, "The log file is in the attachment.");
//FIXME: intentMail.putExtra(Intent.EXTRA_STREAM, attachmentUri);
if(intentMail.resolveActivity(getPackageManager()) != null){
try{
startActivity(intentMail);
}catch (android.content.ActivityNotFoundException ane){
ane.printStackTrace();
Log.e("MAIL", "No email client could be found");
}
}
}
void clearScreen(){
tvLog.setText(null);
}
/* makes it possible to change signalling and log file creation intervals through the EditTexts on UI */
void setIntervals(){
// mSignallingInterval = Integer.parseInt(etSignallingInterval.getText().toString());
// mLoggingInterval = Integer.parseInt(etLoggingInterval.getText().toString());
// SIGNAL_UPDATE_INTERVAL = mSignallingInterval*1000+1;
// LOG_UPDATE_INTERVAL = mLoggingInterval*60*1000+1;
Log.i("LOGGING", "Interval change");
}
/* creates a instance object of fused location class */
FusedLocation getFusedLocationInstance(){
if ( fusedLocation == null ){
fusedLocation = new FusedLocation(this);
}
return fusedLocation;
}
/* gets the coordinates from instantiated object */
String getFusedCoordinates(FusedLocation fusedLocation){
return fusedLocation.buildFusedCoordinates();
}
private static boolean isPlaneModeOn(Context context){
return ( Settings.Global.getInt(context.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0 );
}
void activateTimers(){
/* file create timer: every 60 minutes */
Timer timerFileCreate = new Timer();
TimerTask taskFileCreate = new TimerTask() {
@Override
public void run() {
SignalLogFile = createFileInstance();
signalLogFile = nameFile();
createFile(signalLogFile, SignalLogFile);
Log.i("Logging:","created a new file");
}
};
timerFileCreate.scheduleAtFixedRate(taskFileCreate, DEFAULT_TASK_DELAY, LOG_UPDATE_INTERVAL );
/* file update timer: every 30 seconds */
Timer timerFileInsert = new Timer();
TimerTask taskFileInsert = new TimerTask() {
@Override
public void run() {
Log.i("Logging:","wrote a log");
insertLog(getApplicationContext(), SignalLogFile, buildLog());
}
};
timerFileInsert.scheduleAtFixedRate(taskFileInsert, DEFAULT_TASK_DELAY, SIGNAL_UPDATE_INTERVAL);
updateUI();
}
public void activateAppendLog(){
Log.i("LOC","INTENT SERVICE");
}
void activateButtonListeners(){
/* listens for send email action */
btnSendMail.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.v("MAIL", "Mailing");
sendMail();
}
});
/* listens for interval change action */
btnSetIntervals.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.v("LOG", "Interval change");
setIntervals();
}
}) ;
/* listens for clear screen */
btnClearTv.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
Log.i("LOG", "Cleaned screen");
clearScreen();
}
});
}
boolean checkNetConnectivity(Context context){
connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
networkInfo = connectivityManager.getActiveNetworkInfo();
if (connectivityManager != null ) {
networkInfo = connectivityManager.getActiveNetworkInfo();
}
hasNetConnection = networkInfo != null && networkInfo.isConnected();
return hasNetConnection;
}
/*
24 N Android 7.0 Nougat
25 N_MR1 Android 7.1.1 Nougat
26 O Android 8.0 Oreo
27 O_MR1 Android 8 Oreo MR1
28 P Android P
*/
int getOS_VERSION(){
OS_VERSION = Build.VERSION.SDK_INT;
Log.i("OS VERSION:", Integer.toString(OS_VERSION));
return OS_VERSION;
}
void updateUI(){
/* get location timer: every 30 seconds [changeable on UI via Signalling/Logging interval values] */
Timer timerAppendLog = new Timer();
TimerTask taskAppendLog = new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
tvLog.append(buildLog());
}
});
}
};
timerAppendLog.scheduleAtFixedRate(taskAppendLog, DEFAULT_TASK_DELAY, SIGNAL_UPDATE_INTERVAL);
}
/* starts the background service with explicit intent. never use implicit intents for services,
using implicit intent might cause damage as no service responds to intent's call. also NO
intent filters for services. */
/* background service inherits Service and runs on the main thread. */
void startBackgroundService(){
Intent backgroundServiceIntent = new Intent( this, LocationBackgroundService.class);
startService(backgroundServiceIntent);
}
/* LocationIntentService inherits IntentService and runs on seperate thread. */
void startLocationIntentService(){
Intent locationServiceIntent = new Intent(this, LocationIntentService.class );
startService(locationServiceIntent);
}
@Override
protected void onPause() {
super.onPause();
// stopFusedLocationListen();
}
@Override
protected void onResume() {
super.onResume();
Log.v("RESUME:", getTime());
}
@Override
protected void onRestart() {
super.onRestart();
Log.v("RESTART:", getTime());
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.v("SAVE:", getTime());
}
@Override
protected void onStop() {
super.onStop();
Log.v("STOP:", getTime());
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.v("DESTROY:", getTime());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment