├── .gitignore
├── .idea
├── .name
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── License.txt
├── README.md
├── app
├── .gitignore
├── build.gradle
├── google-services.json
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── edu
│ │ └── buffalo
│ │ └── cse
│ │ └── ubwins
│ │ └── cellmon
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── edu
│ │ │ └── buffalo
│ │ │ └── cse
│ │ │ └── ubwins
│ │ │ └── cellmon
│ │ │ ├── Alarm.java
│ │ │ ├── CellularDataRecorder.java
│ │ │ ├── Cluster.java
│ │ │ ├── Coordinate.java
│ │ │ ├── DBHandler.java
│ │ │ ├── DBstore.java
│ │ │ ├── DatePickerFragment.java
│ │ │ ├── DateSelectedListener.java
│ │ │ ├── Entry.java
│ │ │ ├── ForegroundService.java
│ │ │ ├── HomeFragment.java
│ │ │ ├── LocationFinder.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MapFragment.java
│ │ │ ├── MonthPickerFragment.java
│ │ │ ├── NetworkStateReceiver.java
│ │ │ ├── PhoneCallState.java
│ │ │ ├── PhoneCallStateRecorder.java
│ │ │ ├── ScheduleIntentReceiver.java
│ │ │ ├── Scheduler.java
│ │ │ ├── StartMyServiceAtBootReceiver.java
│ │ │ └── WeekPickerFragment.java
│ ├── proto
│ │ ├── data_record.proto
│ │ └── register_device.proto
│ └── res
│ │ ├── anim
│ │ ├── move_left_in_activity.xml
│ │ ├── move_left_out_activity.xml
│ │ ├── move_right_in_activity.xml
│ │ └── move_right_out_activity.xml
│ │ ├── drawable-hdpi
│ │ ├── drawer_shadow.9.png
│ │ ├── ic_date_range_black_24dp.png
│ │ ├── ic_date_range_white_24dp.png
│ │ └── ic_drawer.png
│ │ ├── drawable-mdpi
│ │ ├── drawer_shadow.9.png
│ │ ├── ic_date_range_black_24dp.png
│ │ ├── ic_date_range_white_24dp.png
│ │ └── ic_drawer.png
│ │ ├── drawable-xhdpi
│ │ ├── drawer_shadow.9.png
│ │ ├── ic_date_range_black_24dp.png
│ │ ├── ic_date_range_white_24dp.png
│ │ └── ic_drawer.png
│ │ ├── drawable-xxhdpi
│ │ ├── ic_date_range_black_24dp.png
│ │ └── ic_date_range_white_24dp.png
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_date_range_black_24dp.png
│ │ └── ic_date_range_white_24dp.png
│ │ ├── drawable
│ │ └── side_nav_bar.xml
│ │ ├── layout
│ │ ├── activity_base.xml
│ │ ├── activity_main.xml
│ │ ├── fragment_pick_week.xml
│ │ ├── location_fragment.xml
│ │ ├── nav_header_main.xml
│ │ └── simple_list_item.xml
│ │ ├── menu
│ │ ├── app_menu.xml
│ │ ├── home_menu.xml
│ │ └── map_menu.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── m.png
│ │ ├── mipmap-mdpi
│ │ ├── cse50.png
│ │ ├── ic_action_about.png
│ │ ├── ic_action_computer.png
│ │ ├── ic_action_place.png
│ │ ├── ic_action_time.png
│ │ ├── ic_globe.png
│ │ ├── ic_launcher.png
│ │ └── m.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── m.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── m.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── m.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ ├── protobuf_autogen
│ └── debug
│ │ └── java
│ │ └── edu
│ │ └── buffalo
│ │ └── cse
│ │ └── ubwins
│ │ └── cellmon
│ │ ├── DataRecordOuterClass.java
│ │ └── RegisterDeviceOuterClass.java
│ └── test
│ └── java
│ └── edu
│ └── buffalo
│ └── cse
│ └── ubwins
│ └── cellmon
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | CellularNetworkMonitor
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Abhishek Gautam, Armaan Goyal and UB Computer Science.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CellularNetworkMonitor
2 |
3 | [](License.txt)
4 |
5 | An Android application that registers your device on to a Django based server keeping IMEI,
6 | carrier service, model make and Android Version as phone identifiers using a HTTP POST.
7 | Serialization of data sent over the network is achieved using [Google Protocol Buffers](https://github.com/google/protobuf)
8 |
9 | # Features:
10 | 1. Tracks location based on NETWORK_PROVIDER (strict and relaxed) and Fused API
11 | 2. Monitors [RSSI](https://en.wikipedia.org/wiki/Received_signal_strength_indication) and DBM levels
12 | 3. Current network state and other network parameters such as MCC, MNC, LAC and CID
13 | 4. Data activity
14 | 5. Stores all data in SQLite DB on local device storage
15 | 6. Reports can be exported in the form of CSV files
16 |
17 | # More to come:
18 | 7. Statistical Analysis in the form of UI
19 | 8. Map UI integration lets you know in what areas you get what Network Reception(both RSSI and data type)
20 |
21 | # UI:
22 | Check out [CellMon-UI](https://github.com/gautamgitspace/CellMon-UI) for the application UI.
23 |
24 | # Protobuf usage, installation and compilation
25 | Check out [my blog](http://www.acsu.buffalo.edu/~agautam2/gistblog/furtherdown/protocolbuffers.html) to get up and running with protocol buffers
26 |
27 | # License
28 | This project is licensed under the [MIT License](https://en.wikipedia.org/wiki/MIT_License).
29 |
30 | Copyright (c) 2016 [Abhishek Gautam](http://www.acsu.buffalo.edu/~agautam2/), [Armaan Goyal](http://www.acsu.buffalo.edu/~armaango/) and [UB Computer Science](https://www.cse.buffalo.edu/)
31 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.google.protobuf" version "0.8.0"
3 | }
4 | apply plugin: 'com.android.application'
5 |
6 | repositories {
7 | maven { url "https://jitpack.io" }
8 | }
9 |
10 | android {
11 | compileSdkVersion 23
12 | buildToolsVersion '25.0.0'
13 |
14 | useLibrary 'org.apache.http.legacy'
15 | defaultConfig {
16 | applicationId "edu.buffalo.cse.ubwins.cellmon"
17 | minSdkVersion 18
18 | targetSdkVersion 21
19 | versionCode 1
20 | versionName "1.0"
21 | multiDexEnabled true
22 | }
23 | buildTypes {
24 | release {
25 | minifyEnabled false
26 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | testCompile 'junit:junit:4.12'
34 | compile 'com.android.support:appcompat-v7:23.4.0'
35 | compile 'com.android.support:design:23.0.1'
36 | compile 'com.android.support:support-v4:23.4.0'
37 | compile 'com.google.android.gms:play-services:10.2.0'
38 | compile 'com.android.support:multidex:1.0.1'
39 | compile 'com.google.protobuf:protobuf-lite:3.0.0'
40 | compile 'com.pushlink:pushlink-android:5.5.0'
41 | compile 'com.facebook.stetho:stetho:1.4.2'
42 | compile 'com.google.maps.android:android-maps-utils:0.5+'
43 | }
44 |
45 | protobuf {
46 | plugins {
47 | javalite {
48 | // The codegen for lite comes as a separate artifact
49 | artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
50 | }
51 |
52 | }
53 | protoc
54 | {
55 | path = '/usr/bin/protoc'
56 | path = '/usr/local/bin/protoc'
57 | }
58 |
59 | generatedFilesBaseDir = "$projectDir/src/protobuf_autogen"
60 |
61 | generateProtoTasks {
62 | all().each { task ->
63 | task.plugins {
64 | javalite {
65 | outputSubDir = 'java'
66 | }
67 | }
68 | }
69 | }
70 | }
71 | apply plugin: 'com.google.gms.google-services'
--------------------------------------------------------------------------------
/app/google-services.json:
--------------------------------------------------------------------------------
1 | {
2 | "project_info": {
3 | "project_number": "62153221471",
4 | "firebase_url": "https://eminent-parsec-158802.firebaseio.com",
5 | "project_id": "eminent-parsec-158802",
6 | "storage_bucket": "eminent-parsec-158802.appspot.com"
7 | },
8 | "client": [
9 | {
10 | "client_info": {
11 | "mobilesdk_app_id": "1:62153221471:android:a6d915737041af62",
12 | "android_client_info": {
13 | "package_name": "edu.buffalo.cse.ubwins.cellmon"
14 | }
15 | },
16 | "oauth_client": [
17 | {
18 | "client_id": "62153221471-fgct8koqqdv56ffieijlhbql0tobhg5g.apps.googleusercontent.com",
19 | "client_type": 3
20 | }
21 | ],
22 | "api_key": [
23 | {
24 | "current_key": "AIzaSyA_ViTr-Tyypip3_ii3H0CcJyHo6i0_t68"
25 | }
26 | ],
27 | "services": {
28 | "analytics_service": {
29 | "status": 1
30 | },
31 | "appinvite_service": {
32 | "status": 1,
33 | "other_platform_oauth_client": []
34 | },
35 | "ads_service": {
36 | "status": 2
37 | }
38 | }
39 | }
40 | ],
41 | "configuration_version": "1"
42 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/Gautam/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/edu/buffalo/cse/ubwins/cellmon/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/Alarm.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.annotation.TargetApi;
4 | import android.app.AlarmManager;
5 | import android.app.PendingIntent;
6 | import android.content.BroadcastReceiver;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.location.LocationManager;
10 | import android.os.AsyncTask;
11 | import android.os.PowerManager;
12 | import android.telephony.TelephonyManager;
13 | import android.util.Base64;
14 | import android.util.Log;
15 |
16 | import com.google.firebase.crash.FirebaseCrash;
17 |
18 | import org.apache.http.HttpResponse;
19 | import org.apache.http.client.ClientProtocolException;
20 | import org.apache.http.client.HttpClient;
21 | import org.apache.http.client.methods.HttpGet;
22 | import org.apache.http.impl.client.DefaultHttpClient;
23 |
24 | import java.io.IOException;
25 | import java.net.URI;
26 | import java.net.URISyntaxException;
27 | import java.net.URLEncoder;
28 | import java.security.MessageDigest;
29 | import java.security.NoSuchAlgorithmException;
30 |
31 | import static android.content.Context.LOCATION_SERVICE;
32 |
33 | /**
34 | * Created by pcoonan on 4/12/17.
35 | */
36 |
37 | public class Alarm extends BroadcastReceiver {
38 | CellularDataRecorder cdr;
39 | PhoneCallStateRecorder pcsr;
40 | DBstore dbStore;
41 | public final String TAG = "[CELNETMON-ALARM]";
42 | static int keepAlive = 0;
43 | String IMEI_HASH;
44 | String IMEI;
45 | public static long lastTime = 0;
46 |
47 | @Override
48 | public void onReceive(Context context, Intent intent) {
49 | // long cur = System.currentTimeMillis();
50 | // Log.d(TAG, "Received alarm trigger since " + ((cur - lastTime)/1000.0));
51 | // PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
52 | // PowerManager.WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
53 | // wakeLock.acquire();
54 |
55 | logData(context);
56 | setAlarm(context);
57 | // wakeLock.release();
58 | }
59 |
60 | @TargetApi(19)
61 | public void setAlarm(Context context){
62 | AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
63 | Intent i = new Intent(context, Alarm.class);
64 | i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
65 | PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
66 | am.setExact(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()+10000, pi);
67 | lastTime = System.currentTimeMillis();
68 | // am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (10000 * offset), 60000, pi);
69 | // Log.d(TAG, "Alarm set!");
70 | }
71 |
72 | public void cancelAlarm(Context context){
73 | Intent intent = new Intent(context, Alarm.class);
74 | PendingIntent sender = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
75 | AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
76 | alarmManager.cancel(sender);
77 | Log.d(TAG, "Alarm cancelled!");
78 | }
79 |
80 | private void logData(Context arg0) {
81 | keepAlive++;
82 |
83 | final TelephonyManager telephonyManager =
84 | (TelephonyManager) arg0.getSystemService(Context.TELEPHONY_SERVICE);
85 | IMEI = telephonyManager.getDeviceId();
86 | cdr = new CellularDataRecorder();
87 | pcsr = new PhoneCallStateRecorder();
88 |
89 | // locationFinder = new LocationFinder(arg0);
90 | //Log.v(TAG, "Calling getLocalTimeStamp and getCellularInfo");
91 |
92 | /*FETCH INFO FROM CDR CLASS*/
93 | Long timeStamp = cdr.getLocalTimeStamp();
94 | String cellularInfo = cdr.getCellularInfo(telephonyManager);
95 | int dataActivity = cdr.getCurrentDataActivity(telephonyManager);
96 | int dataState = cdr.getCurrentDataState(telephonyManager);
97 | int mobileNetworkType = cdr.getMobileNetworkType(telephonyManager);
98 |
99 | final LocationManager locationManager = (LocationManager) arg0.getSystemService(LOCATION_SERVICE);
100 |
101 | if (ForegroundService.FusedApiLatitude == null || ForegroundService.FusedApiLongitude == null) {
102 | return;
103 | }
104 |
105 | /*FETCH INFO FROM FUSED API*/
106 | Double fusedApiLatitude = ForegroundService.FusedApiLatitude;
107 | Double fusedApiLongitude = ForegroundService.FusedApiLongitude;
108 | boolean stale = ((System.currentTimeMillis() - ForegroundService.LastFusedLocation) > 40000)
109 | && dataState == 0 && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
110 |
111 | Double locationdata[] = {fusedApiLatitude, fusedApiLongitude};
112 |
113 |
114 | /*FETCH INFO FROM PCSR CLASS*/
115 | int phoneCallState = PhoneCallStateRecorder.call_state;
116 |
117 | dbStore = new DBstore(arg0);
118 | dbStore.insertIntoDB(locationdata, stale, timeStamp, cellularInfo, dataActivity, dataState,
119 | phoneCallState, mobileNetworkType);
120 |
121 | if (keepAlive == 360) {
122 | new PingTask().execute();
123 | keepAlive = 0;
124 | }
125 | }
126 |
127 | class PingTask extends AsyncTask {
128 |
129 | @Override
130 | protected String doInBackground(String... params) {
131 | String IMEI_HASH = "";
132 | String responseStr = "";
133 | try {
134 | /*HASH IMEI*/
135 | IMEI_HASH = genHash(IMEI);
136 | } catch (NoSuchAlgorithmException e) {
137 | e.printStackTrace();
138 | }
139 | Log.v(TAG, "GENERATED IMEI HASH");
140 | //TODO KEEP-ALIVE GET
141 | HttpResponse response = null;
142 | try {
143 | HttpClient client = new DefaultHttpClient();
144 | HttpGet request = new HttpGet();
145 | String customURL = "http://104.196.177.7/aggregator/ping?imei_hash="
146 | + URLEncoder.encode(IMEI_HASH, "UTF-8");
147 | Log.d(TAG, customURL);
148 | request.setURI(new URI(customURL));
149 | response = client.execute(request);
150 | Log.v(TAG, "RESPONSE PHRASE FOR HTTP GET: "
151 | + response.getStatusLine().getReasonPhrase());
152 | Log.v(TAG, "RESPONSE STATUS FOR HTTP GET: "
153 | + response.getStatusLine().getStatusCode());
154 | responseStr = response.getStatusLine().getReasonPhrase();
155 | } catch (URISyntaxException|IOException e) {
156 | e.printStackTrace();
157 | FirebaseCrash.log("Error in ping task for: " + IMEI_HASH);
158 | }
159 | return responseStr;
160 | }
161 | }
162 |
163 | private String genHash(String input) throws NoSuchAlgorithmException {
164 | String IMEI_Base64 = "";
165 | try {
166 | MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
167 | byte[] sha256Hash = sha256.digest(input.getBytes("UTF-8"));
168 | IMEI_Base64 = Base64.encodeToString(sha256Hash, Base64.DEFAULT);
169 | IMEI_Base64 = IMEI_Base64.replaceAll("\n", "");
170 | } catch (Exception e) {
171 | e.printStackTrace();
172 | }
173 | return IMEI_Base64;
174 | }
175 |
176 |
177 | }
178 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/CellularDataRecorder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gautam on 6/18/16.
3 | * MBP111.0138.B16
4 | * agautam2@buffalo.edu
5 | * University at Buffalo, The State University of New York.
6 | * Copyright © 2016 Gautam. All rights reserved.
7 | */
8 |
9 | package edu.buffalo.cse.ubwins.cellmon;
10 |
11 | import android.telephony.CellIdentityGsm;
12 | import android.telephony.CellIdentityLte;
13 | import android.telephony.CellIdentityWcdma;
14 | import android.telephony.CellIdentityCdma;
15 | import android.telephony.CellInfo;
16 | import android.telephony.CellInfoCdma;
17 | import android.telephony.CellInfoGsm;
18 | import android.telephony.CellInfoLte;
19 | import android.telephony.CellInfoWcdma;
20 | import android.telephony.CellSignalStrengthCdma;
21 | import android.telephony.CellSignalStrengthGsm;
22 | import android.telephony.CellSignalStrengthLte;
23 | import android.telephony.CellSignalStrengthWcdma;
24 | import android.telephony.TelephonyManager;
25 | import android.util.Log;
26 |
27 |
28 |
29 | public class CellularDataRecorder
30 | {
31 |
32 | static final String TAG = "[CELNETMON-CDR]";
33 |
34 | public Long getLocalTimeStamp()
35 | {
36 |
37 | Long timeStamp = System.currentTimeMillis();
38 | return timeStamp;
39 | }
40 |
41 | public int getCurrentDataState(TelephonyManager telephonyManager)
42 | {
43 | int state = telephonyManager.getDataState();
44 | int dataState;
45 |
46 | if (state < 0 || state >3 ){
47 | dataState = -1;
48 | }
49 | else{
50 | dataState =state;
51 | }
52 | return dataState;
53 | }
54 |
55 | public int getCurrentDataActivity(TelephonyManager telephonyManager)
56 | {
57 | int activity = telephonyManager.getDataActivity();
58 | int dataActivity;
59 |
60 | if (activity < 0 || activity > 4 ){
61 | dataActivity = -1;
62 | }
63 | else{
64 | dataActivity =activity;
65 | }
66 | return dataActivity;
67 | }
68 |
69 | public int getMobileNetworkType(TelephonyManager telephonyManager)
70 | {
71 | int networkType = telephonyManager.getNetworkType();
72 |
73 | return networkType;
74 | }
75 |
76 | public String getCellularInfo(TelephonyManager telephonyManager)
77 | {
78 | String cellularInfo = "";
79 | String log = "";
80 | if(telephonyManager.getAllCellInfo()==null) {
81 | Log.v(TAG, "getAllCellInfo returned null");
82 | }
83 | else {
84 | for (final CellInfo info : telephonyManager.getAllCellInfo()) {
85 | if (info instanceof CellInfoGsm) {
86 | log += "GSM@";
87 | CellIdentityGsm gsm_cell = ((CellInfoGsm) info).getCellIdentity();
88 | log += gsm_cell.getCid() + "#" + gsm_cell.getLac() + "#" + gsm_cell.getMcc() + "#" + gsm_cell.getMnc() + "_";
89 |
90 | final CellSignalStrengthGsm gsm = ((CellInfoGsm) info).getCellSignalStrength();
91 | log += gsm.getDbm() + "#" + gsm.getLevel()+"#"+gsm.getAsuLevel()+":";
92 | } else if (info instanceof CellInfoCdma) {
93 | log += "CDMA@";
94 | CellIdentityCdma cdma_cell = ((CellInfoCdma) info).getCellIdentity();
95 | log += cdma_cell.getBasestationId() + "#" + cdma_cell.getNetworkId() + "#" + cdma_cell.getSystemId() + "#" + cdma_cell.getSystemId() + "_";
96 |
97 | final CellSignalStrengthCdma cdma = ((CellInfoCdma) info).getCellSignalStrength();
98 | log += cdma.getDbm() + "#" + cdma.getLevel()+"#"+cdma.getAsuLevel()+":";
99 | } else if (info instanceof CellInfoLte) {
100 | log += "LTE@";
101 | CellIdentityLte lte_cell = ((CellInfoLte) info).getCellIdentity();
102 | log += lte_cell.getCi() + "#" + lte_cell.getPci() + "#" + lte_cell.getMcc() + "#" + lte_cell.getMnc() + "_";
103 |
104 | final CellSignalStrengthLte lte = ((CellInfoLte) info).getCellSignalStrength();
105 | log += lte.getDbm() + "#" + lte.getLevel()+"#"+lte.getAsuLevel()+":";
106 | } else if (info instanceof CellInfoWcdma) {
107 | log += "WCDMA@";
108 | CellIdentityWcdma wcdma_cell = ((CellInfoWcdma) info).getCellIdentity();
109 | log += wcdma_cell.getCid() + "#" + wcdma_cell.getLac() + "#" + wcdma_cell.getMcc() + "#" + wcdma_cell.getMnc() + "_";
110 |
111 | final CellSignalStrengthWcdma wcdma = ((CellInfoWcdma) info).getCellSignalStrength();
112 | log += wcdma.getDbm() + "#" + wcdma.getLevel()+"#"+wcdma.getAsuLevel()+":";
113 | } else {
114 | Log.v(TAG, "Unknown Network Type");
115 | }
116 | }
117 | }
118 | cellularInfo = log;
119 | return cellularInfo;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/Cluster.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 |
7 | /**
8 | * Created by pcoonan on 5/12/17.
9 | */
10 |
11 | public class Cluster {
12 | public List entries;
13 | public Coordinate centroid;
14 | public int id;
15 |
16 | public Cluster(int id){
17 | this.id = id;
18 | this.entries = new ArrayList();
19 | this.centroid = null;
20 | }
21 |
22 | public List getEntries(){
23 | return entries;
24 | }
25 |
26 | public void addEntry(Entry entry){
27 | entries.add(entry);
28 | }
29 |
30 | public void setEntries(List entries){
31 | this.entries = entries;
32 | }
33 |
34 | public Coordinate getCentroid() {
35 | return centroid;
36 | }
37 |
38 | public void setCentroid(Coordinate centroid) {
39 | this.centroid = centroid;
40 | }
41 |
42 | public int getId() {
43 | return id;
44 | }
45 |
46 | public void clear(){
47 | entries.clear();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/Coordinate.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import com.google.android.gms.maps.model.LatLng;
4 |
5 | import java.util.Random;
6 |
7 | /**
8 | * Created by pcoonan on 5/12/17.
9 | */
10 |
11 | public class Coordinate {
12 | private LatLng position;
13 |
14 | public Coordinate(double latitude, double longitude){
15 | this.position = new LatLng(latitude, longitude);
16 | }
17 |
18 | public void setLatitude(double latitude){
19 | this.position = new LatLng(latitude, position.longitude);
20 | }
21 |
22 | public void setLongitude(double longitude){
23 | this.position = new LatLng(position.latitude, longitude);
24 | }
25 |
26 | public double getLatitude(){
27 | return this.position.latitude;
28 | }
29 |
30 | public double getLongitude(){
31 | return this.position.longitude;
32 | }
33 |
34 | public LatLng getPosition(){
35 | return this.position;
36 | }
37 |
38 | protected static double distance(Coordinate c, Coordinate centroid){
39 | return Math.sqrt(
40 | Math.pow((centroid.getLatitude() - c.getLatitude()), 2) +
41 | Math.pow((centroid.getLongitude() - c.getLongitude()), 2));
42 | }
43 |
44 | protected static Coordinate createRandomCoordinate(double maxLat, double minLat,
45 | double minLong, double maxLong){
46 | Random r = new Random();
47 | double latitude = minLat + (maxLat - minLat) * r.nextDouble();
48 | double longitude = minLong + (maxLong - minLong) * r.nextDouble();
49 | return new Coordinate(latitude, longitude);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/DBHandler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gautam on 6/18/16.
3 | * MBP111.0138.B16
4 | * agautam2@buffalo.edu
5 | * University at Buffalo, The State University of New York.
6 | * Copyright © 2016 Gautam. All rights reserved.
7 | */
8 | package edu.buffalo.cse.ubwins.cellmon;
9 |
10 | import android.content.Context;
11 | import android.database.sqlite.SQLiteDatabase;
12 | import android.database.sqlite.SQLiteOpenHelper;
13 | import android.util.Log;
14 |
15 | /*Understanding of SQLite for Android - http://developer.android.com/training/basics/data-storage/databases.html */
16 |
17 | public class DBHandler extends SQLiteOpenHelper
18 | {
19 | private static String dbName="mainTuple";
20 | private static String dbNameBatt="mainTuple";
21 | private static int version=2;
22 | static final String TAG = "[CELNETMON-DBHANDLER]";
23 |
24 | private static final String schema = "CREATE TABLE cellRecords (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, F_LAT DATA, F_LONG DATA, F_STALE DATA, TIMESTAMP DATA, NETWORK_TYPE DATA, NETWORK_TYPE2 DATA, NETWORK_PARAM1 DATA, NETWORK_PARAM2 DATA, NETWORK_PARAM3 DATA, NETWORK_PARAM4 DATA, DBM DATA, NETWORK_LEVEL DATA,ASU_LEVEL DATA, DATA_STATE DATA, DATA_ACTIVITY DATA, CALL_STATE DATA)";
25 | private static final String mapSchema = "CREATE TABLE mapRecords (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, F_LAT DATA, F_LONG DATA, F_STALE DATA, TIMESTAMP DATA, NETWORK_TYPE DATA, NETWORK_TYPE2 DATA, NETWORK_PARAM1 DATA, NETWORK_PARAM2 DATA, NETWORK_PARAM3 DATA, NETWORK_PARAM4 DATA, DBM DATA, NETWORK_LEVEL DATA,ASU_LEVEL DATA, DATA_STATE DATA, DATA_ACTIVITY DATA, CALL_STATE DATA)";
26 | private static final String schemeBatteryStatus = "CREATE TABLE batteryStatus (TIMESTAMP DATA, BATTERY_LEVEL DATA)";
27 | public DBHandler(Context context)
28 |
29 | {
30 | super(context, dbName, null, version);
31 | }
32 |
33 | @Override
34 | public void onCreate(SQLiteDatabase db)
35 | {
36 | db.execSQL(schema);
37 | Log.v(TAG, "CREATING DB " + dbName + "WITH TABLE cellRecords");
38 | db.execSQL(mapSchema);
39 | db.execSQL(schemeBatteryStatus);
40 | Log.v(TAG, "CREATING DB " + dbNameBatt + "WITH TABLE batteryStatus");
41 | }
42 |
43 | @Override
44 | public void onUpgrade(SQLiteDatabase db, int obsolete, int latest)
45 | {
46 | //logic understood from - http://stackoverflow.com/questions/3675032/drop-existing-table-in-sqlite-when-if-exists-operator-is-not-supported
47 | db.execSQL("DROP TABLE IF EXISTS cellRecords");
48 | db.execSQL("DROP TABLE IF EXISTS mapRecords");
49 | db.execSQL("DROP TABLE IF EXISTS batteryStatus");
50 | onCreate(db);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/DBstore.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gautam on 6/18/16.
3 | * MBP111.0138.B16
4 | * agautam2@buffalo.edu
5 | * University at Buffalo, The State University of New York.
6 | * Copyright © 2016 Gautam. All rights reserved.
7 | */
8 |
9 | package edu.buffalo.cse.ubwins.cellmon;
10 |
11 | import android.content.ContentValues;
12 | import android.content.Context;
13 | import android.database.DatabaseUtils;
14 | import android.database.sqlite.SQLiteDatabase;
15 | import android.location.LocationManager;
16 |
17 | import com.google.firebase.crash.FirebaseCrash;
18 |
19 |
20 | public class DBstore
21 | {
22 | static final String TAG = "[CELNETMON-DBSTORE]";
23 | private final Context mContext;
24 |
25 |
26 | public DBstore(Context context)
27 | {
28 | this.mContext=context;
29 | }
30 |
31 | public void insertIntoDB(Double[] locationdata, boolean stale, Long timeStamp,
32 | String cellularInfo, int dataActivity, int dataState,
33 | int phoneCallState, int mobileNetworkType)
34 | {
35 | String networkType = "";
36 | int networkTypeval = -1;
37 | String networkState = "";
38 | String networkStateVariables[]={"","","",""};
39 | String networkRSSI = "";
40 | String networkRSSIVariables[]={"",""};
41 | ContentValues contentValues = new ContentValues();
42 | DBHandler dbHandler = new DBHandler(mContext);
43 | SQLiteDatabase sqLiteDatabase = dbHandler.getWritableDatabase();
44 |
45 | if(!(cellularInfo.equals("")))
46 | {
47 |
48 | // Log.v(TAG, "before split: " + cellularInfo);
49 | String[] mainsplit = cellularInfo.split(":");
50 | String[] splitter = mainsplit[0].split("@");
51 | //Log.v(TAG, "splitter of zero: " + splitter[0]);
52 | //Log.v(TAG, "splitter of one: " + splitter[1]);
53 | networkType = splitter[0];
54 | String splitter1[] = splitter[1].split("_");
55 | networkState = splitter1[0];
56 | networkStateVariables = networkState.split("#");
57 |
58 | //Log.v(TAG, "splitter1 of zero: " + splitter1[0]);
59 | //Log.v(TAG, "splitter1 of one: " + splitter1[1]);
60 | networkRSSI = splitter1[1];
61 | networkRSSIVariables = networkRSSI.split("#");
62 | }
63 | else{
64 | FirebaseCrash.log("Cellular info equals an empty string");
65 | sqLiteDatabase.close();
66 | return;
67 | }
68 |
69 | if (networkType!=null && networkType.equals("GSM")){
70 | networkTypeval = 0;
71 | }
72 | else if (networkType!=null && networkType.equals("CDMA")){
73 | networkTypeval = 1;
74 | }
75 | else if (networkType!=null && networkType.equals("LTE")){
76 | networkTypeval = 2;
77 | }
78 | else if (networkType!=null && networkType.equals("WCDMA")){
79 | networkTypeval = 3;
80 | }
81 | //Log.v(TAG,"Trying to push to DB");
82 |
83 | contentValues.put("F_LAT",locationdata[0]);
84 | contentValues.put("F_LONG",locationdata[1]);
85 | contentValues.put("F_STALE", stale);
86 | contentValues.put("TIMESTAMP",timeStamp);
87 | contentValues.put("NETWORK_TYPE", networkTypeval);
88 | contentValues.put("NETWORK_TYPE2", mobileNetworkType);
89 | contentValues.put("NETWORK_PARAM1", Integer.parseInt(networkStateVariables[0]));
90 | contentValues.put("NETWORK_PARAM2", Integer.parseInt(networkStateVariables[1]));
91 | contentValues.put("NETWORK_PARAM3", Integer.parseInt(networkStateVariables[2]));
92 | contentValues.put("NETWORK_PARAM4", Integer.parseInt(networkStateVariables[3]));
93 | contentValues.put("DBM", Integer.parseInt(networkRSSIVariables[0]));
94 | contentValues.put("NETWORK_LEVEL", Integer.parseInt(networkRSSIVariables[1]));
95 | contentValues.put("ASU_LEVEL",Integer.parseInt(networkRSSIVariables[2]));
96 | contentValues.put("DATA_STATE",dataState);
97 | contentValues.put("DATA_ACTIVITY", dataActivity);
98 | contentValues.put("CALL_STATE",phoneCallState);
99 |
100 | sqLiteDatabase.insert("cellRecords", null, contentValues);
101 |
102 | // Only store one hour of data for map testing
103 | long mapCount = DatabaseUtils.queryNumEntries(sqLiteDatabase, "mapRecords");
104 | if(mapCount < 1200){
105 | sqLiteDatabase.insert("mapRecords", null, contentValues);
106 | }
107 | sqLiteDatabase.close();
108 | //Log.v(TAG,"Push to DB Successful");
109 | }
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/DatePickerFragment.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.Dialog;
4 | import android.app.DialogFragment;
5 | import android.app.DatePickerDialog;
6 | import android.os.Bundle;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.DatePicker;
10 |
11 | import java.text.SimpleDateFormat;
12 | import java.util.Calendar;
13 |
14 | import static android.R.attr.max;
15 | import static android.R.attr.minDate;
16 | import static android.media.CamcorderProfile.get;
17 | import static android.os.Build.VERSION_CODES.M;
18 |
19 | /**
20 | * Created by pcoonan on 3/31/17.
21 | */
22 |
23 | public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
24 |
25 | public final String TAG = "[CELNETMON-DATEFRAG]";
26 | // public static String selectedItem;
27 | public static Integer selectedYear;
28 | public static Integer selectedMonth;
29 | public static Integer selectedDay;
30 |
31 | public static DatePickerFragment newInstance(long mindate){
32 | DatePickerFragment fragment = new DatePickerFragment();
33 |
34 | Bundle args = new Bundle();
35 | args.putLong("mindate", mindate);
36 | fragment.setArguments(args);
37 |
38 | return fragment;
39 | }
40 | @Override
41 | public Dialog onCreateDialog(Bundle savedInstanceState){
42 | Long mindate = getArguments().getLong("mindate");
43 | final Calendar maxDate = Calendar.getInstance();
44 | maxDate.add(Calendar.DATE, -2);
45 |
46 | int year = maxDate.get(Calendar.YEAR);
47 | int month = maxDate.get(Calendar.MONTH);
48 | int day = maxDate.get(Calendar.DAY_OF_MONTH);
49 |
50 | selectedYear = (selectedYear == null) ? year : selectedYear;
51 | selectedMonth = (selectedMonth == null) ? month : selectedMonth;
52 | selectedDay = (selectedDay == null) ? day : selectedDay;
53 | DatePickerDialog dpd = new DatePickerDialog(getActivity(),
54 | this, selectedYear, selectedMonth, selectedDay);
55 |
56 | dpd.getDatePicker().setMaxDate(maxDate.getTimeInMillis());
57 | dpd.getDatePicker().setMinDate(mindate);
58 | return dpd;
59 | }
60 |
61 | @Override
62 | public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
63 | // Log.d(TAG, "Date selected: DAY:" + dayOfMonth + " MONTH:" + monthOfYear + " YEAR:" + year);
64 | selectedDay = dayOfMonth;
65 | selectedMonth = monthOfYear;
66 | selectedYear = year;
67 | sendBackResult();
68 | }
69 |
70 | public void sendBackResult(){
71 | DateSelectedListener listener = (DateSelectedListener) getTargetFragment();
72 | // Need to add one to month index for conversion back to millis
73 | listener.onFinishSelect("day", (selectedMonth+1) + "/" + selectedDay + "/" + selectedYear);
74 | dismiss();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/DateSelectedListener.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | /**
4 | * Created by pcoonan on 4/6/17.
5 | */
6 |
7 | public interface DateSelectedListener {
8 | void onFinishSelect(String type, String value);
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/Entry.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import com.google.android.gms.maps.model.LatLng;
4 | import com.google.maps.android.clustering.ClusterItem;
5 |
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | /**
10 | * Created by patrick on 5/2/17.
11 | */
12 |
13 | public class Entry implements ClusterItem{
14 | public long timestamp;
15 | // public double latitude;
16 | // public double longitude;
17 | public Coordinate coordinate;
18 | public int networkCellType;
19 | public int dbm;
20 | public int signalLevel;
21 | public int clusterNumber = 0;
22 |
23 | private Entry(){};
24 | public static Entry mapJSON(JSONObject object) throws JSONException {
25 | Entry ret = new Entry();
26 | ret.timestamp = object.getLong("timestamp");
27 | // ret.latitude = object.getDouble("fused_lat");
28 | // ret.longitude = object.getDouble("fused_long");
29 | ret.coordinate = new Coordinate(object.getDouble("fused_lat"),object.getDouble("fused_long"));
30 | ret.networkCellType = object.getInt("network_cell_type");
31 | ret.dbm = object.getInt("signal_dbm");
32 | ret.signalLevel = object.getInt("signal_level");
33 | return ret;
34 | }
35 |
36 | @Override
37 | public LatLng getPosition() {
38 | return coordinate.getPosition();
39 | }
40 |
41 | @Override
42 | public String getTitle() {
43 | return String.valueOf(timestamp);
44 | }
45 |
46 | @Override
47 | public String getSnippet() {
48 | return String.valueOf(dbm);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/ForegroundService.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.Activity;
4 | import android.app.Notification;
5 | import android.app.PendingIntent;
6 | import android.app.Service;
7 | import android.content.BroadcastReceiver;
8 | import android.content.ContentValues;
9 | import android.content.Context;
10 | import android.content.Intent;
11 | import android.content.IntentFilter;
12 | import android.content.SharedPreferences;
13 | import android.database.Cursor;
14 | import android.database.sqlite.SQLiteDatabase;
15 | import android.location.Location;
16 | import android.net.ConnectivityManager;
17 | import android.net.NetworkInfo;
18 | import android.os.AsyncTask;
19 | import android.os.BatteryManager;
20 | import android.os.Bundle;
21 | import android.os.Environment;
22 | import android.os.IBinder;
23 | import android.os.PowerManager;
24 | import android.support.v4.app.NotificationCompat;
25 | import android.telephony.TelephonyManager;
26 | import android.util.Base64;
27 | import android.util.Log;
28 | import android.widget.Toast;
29 | import com.google.android.gms.common.ConnectionResult;
30 | import com.google.android.gms.common.api.GoogleApiClient;
31 | import com.google.android.gms.location.LocationListener;
32 | import com.google.android.gms.location.LocationRequest;
33 | import com.google.android.gms.location.LocationServices;
34 |
35 | import org.apache.http.HttpResponse;
36 | import org.apache.http.client.HttpClient;
37 | import org.apache.http.client.methods.HttpPost;
38 | import org.apache.http.entity.ByteArrayEntity;
39 | import org.apache.http.impl.client.DefaultHttpClient;
40 | import org.apache.http.util.EntityUtils;
41 | import org.json.JSONObject;
42 |
43 | import java.io.File;
44 | import java.io.FileWriter;
45 | import java.io.IOException;
46 | import java.io.PrintWriter;
47 | import java.security.MessageDigest;
48 | import java.security.NoSuchAlgorithmException;
49 |
50 | import static edu.buffalo.cse.ubwins.cellmon.Scheduler.scheduler;
51 |
52 | public class ForegroundService extends Service implements
53 | GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
54 | LocationListener
55 | {
56 | private static final String LOG_TAG = "ForegroundService";
57 |
58 | ScheduleIntentReceiver scheduleIntentReceiver;
59 | // Scheduler scheduler;
60 | private GoogleApiClient mGoogleApiClient;
61 | public LocationRequest mLocationRequest;
62 | public static Double FusedApiLatitude;
63 | public static Double FusedApiLongitude;
64 | public static long LastFusedLocation;
65 |
66 | public static int TYPE_WIFI = 1;
67 | public static int TYPE_MOBILE = 2;
68 | public static int TYPE_NOT_CONNECTED = 0;
69 |
70 | String URL_UPLOAD = "http://104.196.177.7:80/aggregator/upload/";
71 | String responsePhrase;
72 | String statusPhraseLogger;
73 | String recordsPhraseLogger;
74 | String IMEI_TO_POST;
75 | static PrintWriter printWriter = null;
76 |
77 | private SQLiteDatabase sqLiteDatabase;
78 |
79 | // Originally 5 hours and 12000 entries
80 | static int hoursPerUpload = 5;
81 | static int entriesToUpload = 12000;
82 | File exportDir;
83 | Alarm alarm = new Alarm();
84 | private Scheduler scheduler;
85 |
86 | PowerManager.WakeLock wakeLock;
87 | SharedPreferences preferences;
88 | static FileWriter fileWriter = null;
89 | static File file = null;
90 | ContentValues contentValues = new ContentValues();
91 |
92 | public final String TAG = "[CELMON-FRGRNDSRVC]";
93 |
94 | public static void initPrintWriter(File file)
95 | {
96 | try
97 | {
98 | printWriter = new PrintWriter(new FileWriter(file,true));
99 | }
100 | catch(IOException e)
101 | {
102 | e.printStackTrace();
103 | }
104 | }
105 |
106 |
107 | @Override
108 | public void onCreate()
109 | {
110 | super.onCreate();
111 | buildGoogleApiClient();
112 | scheduleIntentReceiver = new ScheduleIntentReceiver();
113 | scheduler = new Scheduler();
114 | Log.v(LOG_TAG, "Creating Scheduler Instance");
115 |
116 | IntentFilter filter = new IntentFilter();
117 | filter.addAction("android.intent.action.ACTION_POWER_CONNECTED");
118 | filter.addAction("android.intent.action.ACTION_POWER_DISCONNECTED");
119 | filter.addAction(Intent.ACTION_BATTERY_CHANGED);
120 |
121 | registerReceiver(receiver, filter);
122 |
123 | String state = Environment.getExternalStorageState();
124 | if (!Environment.MEDIA_MOUNTED.equals(state))
125 | {
126 | Log.v(TAG, "MEDIA MOUNT ERROR!");
127 | }
128 | else {
129 | exportDir =
130 | Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
131 |
132 | if (!exportDir.exists())
133 | {
134 | exportDir.mkdirs();
135 | Log.v(TAG, "Directory made");
136 | }
137 |
138 | File file = new File(exportDir.getAbsolutePath() + "BatteryLevel.csv");
139 |
140 | if(!file.exists())
141 | {
142 | try
143 | {
144 | Log.v(TAG, "CREATING FILE at " + exportDir.getAbsolutePath());
145 | file.createNewFile();
146 | initPrintWriter(file);
147 | printWriter.write("TIMESTAMP, BATTERY_LEVEL");
148 | }
149 | catch(IOException ex)
150 | {
151 | ex.printStackTrace();
152 | }
153 | }
154 |
155 | }
156 | }
157 |
158 | @Override
159 | public int onStartCommand(Intent intent, int flags, int startId)
160 | {
161 |
162 | if(null == intent){
163 | return START_STICKY;
164 | }
165 | else if(null == intent.getAction()){
166 | return START_STICKY;
167 | }
168 |
169 | if (intent.getAction().equals("startforeground"))
170 | {
171 | Log.i(LOG_TAG, "Received Start Foreground Intent ");
172 | Intent notificationIntent = new Intent(this, MainActivity.class);
173 | notificationIntent.setAction("mainAction");
174 | notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
175 | | Intent.FLAG_ACTIVITY_CLEAR_TASK);
176 | PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
177 | notificationIntent, 0);
178 |
179 | Notification notification = new NotificationCompat.Builder(this)
180 | .setContentTitle("CellularNetworkMonitor is running")
181 | .setSmallIcon(R.mipmap.m)
182 | .setContentIntent(pendingIntent)
183 | .setOngoing(true)
184 | .build();
185 | startForeground(101,
186 | notification);
187 |
188 | /*ACQUIRING WAKELOCK*/
189 | // PowerManager mgr =
190 | // (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
191 | // wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
192 | // wakeLock.acquire();
193 | // Log.v(LOG_TAG, "Acquired WakeLock");
194 |
195 | mGoogleApiClient.connect();
196 | //finished connecting API Client
197 | // locationFinder = new LocationFinder(getApplicationContext());
198 | //calling getLocation() from Location provider
199 | // locationFinder.getLocation();
200 |
201 | /*CALL TO SCHEDULER METHOD*/
202 | alarm.setAlarm(this);
203 |
204 | // scheduler.beep(getApplicationContext());
205 | //Log.v(LOG_TAG, "SCHEDULER SET TO BEEP Every second");
206 | Toast.makeText(getApplicationContext(),
207 | "Tracking set to ON!", Toast.LENGTH_SHORT).show();
208 |
209 | }
210 | else if (intent.getAction().equals("stopforeground"))
211 | {
212 | /*CANCEL SCHEDULER AND RELEASE WAKELOCK*/
213 | // if(wakeLock.isHeld()) {
214 | // wakeLock.release();
215 | // }
216 | //Log.v(LOG_TAG, "Releasing WakeLock");
217 | alarm.cancelAlarm(this);
218 |
219 | // Scheduler.stopScheduler();
220 | //Log.v(LOG_TAG, "Beeping Service Stoppped");
221 |
222 | /*to disconnect google api client*/
223 | if(mGoogleApiClient.isConnected())
224 | {
225 | mGoogleApiClient.disconnect();
226 | }
227 | stopForeground(true);
228 | stopSelf();
229 | Toast.makeText(getApplicationContext(),
230 | "Tracking set to OFF!", Toast.LENGTH_SHORT).show();
231 | }
232 | return START_STICKY;
233 | }
234 |
235 | @Override
236 | public void onDestroy() {
237 | super.onDestroy();
238 | unregisterReceiver(receiver);
239 | Log.i(LOG_TAG, "In onDestroy");
240 | }
241 |
242 | @Override
243 | public IBinder onBind(Intent intent) {
244 | // Used only in case of bound services.
245 | return null;
246 | }
247 |
248 | @Override
249 | public void onConnected(Bundle bundle) {
250 | mLocationRequest = LocationRequest.create();
251 | mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
252 | mLocationRequest.setInterval(10000);
253 | try {
254 | LocationServices.FusedLocationApi.requestLocationUpdates(
255 | mGoogleApiClient, mLocationRequest, this);
256 | }
257 | catch (SecurityException e)
258 | {
259 | e.printStackTrace();
260 | }
261 | }
262 |
263 | @Override
264 | public void onLocationChanged(Location location)
265 | {
266 | FusedApiLatitude = location.getLatitude();
267 | FusedApiLongitude = location.getLongitude();
268 | LastFusedLocation = System.currentTimeMillis();
269 | }
270 |
271 | @Override
272 | public void onConnectionSuspended(int i)
273 | {
274 | Log.i(LOG_TAG,"Google Api client has been suspended");
275 | mGoogleApiClient.connect();
276 | }
277 |
278 | @Override
279 | public void onConnectionFailed(ConnectionResult connectionResult){
280 | Log.i(LOG_TAG,"Google Api client connection has failed");
281 | }
282 | protected synchronized void buildGoogleApiClient() {
283 | mGoogleApiClient = new GoogleApiClient.Builder(this)
284 | .addConnectionCallbacks(this)
285 | .addOnConnectionFailedListener(this)
286 | .addApi(LocationServices.API)
287 | .build();
288 | }
289 |
290 | private final BroadcastReceiver receiver = new BroadcastReceiver()
291 | {
292 | boolean isCharging = false;
293 | @Override
294 | public void onReceive(Context context, Intent intent)
295 | {
296 | Long timeStamp;
297 | String action = intent.getAction();
298 | if(action.equals("android.intent.action.ACTION_POWER_CONNECTED"))
299 | {
300 | /*ACTION: CHARGING*/
301 | Log.e("FS","Charging");
302 |
303 | /*LOG BATTERY STATUS - WRITE TO CSV DIRECTLY*/
304 | try
305 | {
306 | IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
307 | Intent batteryStatus = context.registerReceiver(null, ifilter);
308 |
309 | timeStamp = System.currentTimeMillis();
310 | int batteryLevel = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
311 | int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
312 | float batteryPct = (batteryLevel / (float)scale)*100;
313 |
314 | String batteryPctStr = String.valueOf(batteryPct);
315 |
316 | Toast.makeText(getApplicationContext(), batteryPctStr , Toast.LENGTH_SHORT).show();
317 |
318 | String record = timeStamp + "," + batteryPct;
319 | Log.v(TAG, "attempting to write battery status to log file");
320 | File file = new File(exportDir.getAbsolutePath() + "BatteryLevel.csv");
321 | if(file.exists())
322 | {
323 | initPrintWriter(file);
324 | printWriter.println(record);
325 | }
326 | }
327 | catch(Exception exc)
328 | {
329 | exc.printStackTrace();
330 | }
331 | finally
332 | {
333 | if(printWriter != null) printWriter.close();
334 | }
335 |
336 | /*CHECK FOR WIFI*/
337 | isCharging = true;
338 | int count = 0;
339 |
340 | /*UPLOAD 40 HOURS OF DATA IN ONE GO*/
341 | while (isCharging && count <= 15)
342 | {
343 | //Log.v("FS","Charging: inside while loop");
344 | int status = getConnectivityStatus(getApplicationContext());
345 | if(status == TYPE_WIFI)
346 | {
347 | String res = onFetchClicked();
348 | if(res.equals("DB_EMPTY")||res.equals("Data not stale enough"))
349 | {
350 | break;
351 | }
352 | count += 1;
353 | }
354 | else if(status == TYPE_MOBILE || status == TYPE_NOT_CONNECTED)
355 | {
356 | /*WI-FI DISCONNECTED. STOP UPLOADING HERE*/
357 | break;
358 | }
359 | }
360 | }
361 | else if(action.equals("android.intent.action.ACTION_POWER_DISCONNECTED"))
362 | {
363 | /*ACTION: NOT CHARGING*/
364 | Log.e("FS","Not Charging");
365 | isCharging = false;
366 |
367 | /*WRITE TO CSV DIRECTLY*/
368 | try
369 | {
370 | IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
371 | Intent batteryStatus = context.registerReceiver(null, ifilter);
372 |
373 | timeStamp = System.currentTimeMillis();
374 |
375 | int batteryLevel = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
376 | int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
377 | float batteryPct = (batteryLevel / (float)scale)*100;
378 | String batteryPctStr = String.valueOf(batteryPct);
379 |
380 | Toast.makeText(getApplicationContext(), batteryPctStr , Toast.LENGTH_SHORT).show();
381 |
382 | String record = timeStamp + "," + batteryPct;
383 | Log.v(TAG, "attempting to write battery status to log file");
384 | File file = new File(exportDir.getAbsolutePath() + "BatteryLevel.csv");
385 | if(file.exists())
386 | {
387 | initPrintWriter(file);
388 | printWriter.println(record);
389 | }
390 | }
391 | catch(Exception exc)
392 | {
393 | exc.printStackTrace();
394 | }
395 | finally
396 | {
397 | if(printWriter != null) printWriter.close();
398 | }
399 | }
400 | }
401 | };
402 |
403 | public static int getConnectivityStatus(Context context)
404 | {
405 | ConnectivityManager cm =
406 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
407 |
408 | NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
409 | if (null != activeNetwork)
410 | {
411 | if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
412 | return TYPE_WIFI;
413 |
414 | if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
415 | return TYPE_MOBILE;
416 | }
417 | return TYPE_NOT_CONNECTED;
418 | }
419 |
420 | public String onFetchClicked()
421 | {
422 | boolean isConnected = isConnected();
423 | String res = "";
424 | if(isConnected)
425 | {
426 | //Log.v(TAG, "isConnected = TRUE");
427 | try {
428 | res = new LogAsyncTask().execute(URL_UPLOAD).get();
429 | }
430 | catch(Exception e)
431 | {
432 | e.printStackTrace();
433 | }
434 | }
435 | else
436 | {
437 | Log.v(LOG_TAG, "isConnected = FALSE");
438 | Toast.makeText(getBaseContext(),
439 | "Device has no Internet Connectivity! " +
440 | "Please check your Network Connection and try again",
441 | Toast.LENGTH_LONG).show();
442 | }
443 | return res;
444 | }
445 |
446 | private class LogAsyncTask extends AsyncTask
447 | {
448 | @Override
449 | protected String doInBackground(String... urls)
450 | {
451 | Log.v(LOG_TAG, "inside LogAsyncTask");
452 | return LOG_POST(urls[0]);
453 | }
454 | @Override
455 | protected void onPostExecute(String result)
456 | {
457 | //Toast.makeText(getBaseContext(), "Attempt to POST made!", Toast.LENGTH_LONG).show();
458 | }
459 | }
460 |
461 |
462 |
463 | public String LOG_POST(String url)
464 | {
465 | String TEMP_TAG = "[CURSOR_DATA] : ";
466 | int statusCode;
467 | String result = "";
468 |
469 | Cursor cursor = fetchTopFromDB(entriesToUpload);
470 | int count = cursor.getCount();
471 | DataRecordOuterClass.DataRecord.Builder dataRecord =
472 | DataRecordOuterClass.DataRecord.newBuilder();
473 | DataRecordOuterClass.DataRecord recordToSend;
474 | boolean uploadflag = true;
475 |
476 | if(cursor.moveToFirst()) {
477 | long timeStamp = cursor.getLong(4);
478 | long currTimestamp = System.currentTimeMillis();
479 | long timeGap = currTimestamp - timeStamp;
480 | if(timeGap < hoursPerUpload*60*60*1000)
481 | {
482 | uploadflag = false;
483 | result = "Data not stale enough";
484 | }
485 | }
486 |
487 | if (cursor.moveToFirst() && uploadflag)
488 | {
489 | String IMEI = getIMEI();
490 | String networkOperatorCode = getNetworkOperatorCode();
491 | String networkOperatorName = getNetworkOperatorName();
492 |
493 | try{
494 | IMEI_TO_POST = genHash(IMEI);
495 | }
496 | catch(NoSuchAlgorithmException nsa)
497 | {
498 | nsa.printStackTrace();
499 | }
500 | dataRecord.setIMEIHASH(IMEI_TO_POST);
501 | dataRecord.setNETWORKOPERATORNAME(networkOperatorName);
502 | dataRecord.setNETWORKOPERATORCODE(networkOperatorCode);
503 |
504 | do {
505 | dataRecord.addENTRY(DataRecordOuterClass.DataEntry.newBuilder()
506 | .setFUSEDLAT(cursor.getDouble(1))
507 | .setFUSEDLONG(cursor.getDouble(2))
508 | .setSTALE(cursor.getInt(3) > 0)
509 | .setTIMESTAMP(cursor.getLong(4))
510 | .setNETWORKCELLTYPEValue(cursor.getInt(5))
511 | .setNETWORKTYPEValue(cursor.getInt(6))
512 | .setNETWORKPARAM1(cursor.getInt(7))
513 | .setNETWORKPARAM2(cursor.getInt(8))
514 | .setNETWORKPARAM3(cursor.getInt(9))
515 | .setNETWORKPARAM4(cursor.getInt(10))
516 | .setSIGNALDBM(cursor.getInt(11))
517 | .setSIGNALLEVEL(cursor.getInt(12))
518 | .setSIGNALASULEVEL(cursor.getInt(13))
519 | .setNETWORKSTATEValue(cursor.getInt(14))
520 | .setNETWORKDATAACTIVITYValue(cursor.getInt(15))
521 | .setVOICECALLSTATEValue(cursor.getInt(16)).build());
522 |
523 | recordToSend = dataRecord.build();
524 | } while (cursor.moveToNext());
525 |
526 | byte[] logToSend = recordToSend.toByteArray();
527 | int len = logToSend.length;
528 | Log.e("SIZE","Length of 5 entries is : "+len);
529 |
530 |
531 |
532 | try {
533 |
534 | /*1. create HttpClient*/
535 | HttpClient httpclient = new DefaultHttpClient();
536 |
537 | /*2. make POST request to the given URL*/
538 | HttpPost httpPost = new HttpPost(url);
539 |
540 | /*3. Build ByteArrayEntity*/
541 | ByteArrayEntity byteArrayEntity = new ByteArrayEntity(logToSend);
542 |
543 | /*4. Set httpPost Entity*/
544 | httpPost.setEntity(byteArrayEntity);
545 |
546 | /*5. Execute POST request to the given URL*/
547 | HttpResponse httpResponse = httpclient.execute(httpPost);
548 |
549 | /*9. receive response as inputStream*/
550 | statusCode = httpResponse.getStatusLine().getStatusCode();
551 |
552 | /*CONVERT INPUT STREAM TO STRING*/
553 | responsePhrase = EntityUtils.toString(httpResponse.getEntity());
554 | Log.v(LOG_TAG, "RESPONSE" + responsePhrase);
555 |
556 | /*PARSE JSON RESPONSE*/
557 | JSONObject jsonObject = new JSONObject(responsePhrase);
558 | recordsPhraseLogger = jsonObject.getString("records");
559 | statusPhraseLogger = jsonObject.getString("status");
560 |
561 | // Log.e(LOG_TAG, "STATUS: " + statusPhraseLogger);
562 | // Log.e(LOG_TAG, "RECORDS INSERTED: " + recordsPhraseLogger);
563 |
564 | /*DELETE FROM DB IF NO OF RECORDS FETCHED == NO OF RECORDS INSERTED*/
565 | if(Integer.parseInt(recordsPhraseLogger)==count)
566 | {
567 | Log.e(LOG_TAG, "Attempting to delete from DB");
568 | String rawQuery =
569 | "DELETE FROM cellRecords WHERE ID IN " +
570 | "(SELECT ID FROM cellRecords ORDER BY TIMESTAMP LIMIT " +
571 | count + ");";
572 | DBHandler dbHandler = new DBHandler(getApplicationContext());
573 | SQLiteDatabase sqLiteDatabase = dbHandler.getWritableDatabase();
574 | sqLiteDatabase.beginTransaction();
575 | sqLiteDatabase.execSQL(rawQuery);
576 | sqLiteDatabase.setTransactionSuccessful();
577 | sqLiteDatabase.endTransaction();
578 | sqLiteDatabase.close();
579 | }
580 |
581 |
582 | if (statusCode != 404)
583 | {
584 | result = Integer.toString(statusCode);
585 | Log.v(LOG_TAG, "STATUS CODE: " + result);
586 | }
587 | else
588 | {
589 | result = Integer.toString(statusCode);
590 | Log.v(LOG_TAG, "STATUS CODE: " + result);
591 | }
592 | }
593 | catch (Exception e)
594 | {
595 | e.printStackTrace();
596 | }
597 | }
598 | else
599 | {
600 | Log.e(TEMP_TAG, "DB IS BROKE AS HELL!");
601 | result = "DB_EMPTY";
602 | }
603 | sqLiteDatabase.close();
604 | return result;
605 | }
606 | private String getIMEI() {
607 | TelephonyManager telephonyManager =
608 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
609 | return telephonyManager.getDeviceId();
610 | }
611 |
612 | private String getNetworkOperatorCode() {
613 | TelephonyManager telephonyManager =
614 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
615 | return telephonyManager.getNetworkOperator();
616 | }
617 |
618 | private String getNetworkOperatorName() {
619 | TelephonyManager telephonyManager =
620 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
621 | return telephonyManager.getNetworkOperatorName();
622 | }
623 | private String genHash(String input) throws NoSuchAlgorithmException
624 | {
625 | String IMEI_Base64="";
626 | try
627 | {
628 | MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
629 | byte[] sha256Hash = sha256.digest(input.getBytes("UTF-8"));
630 | IMEI_Base64 = Base64.encodeToString(sha256Hash, Base64.DEFAULT);
631 | IMEI_Base64=IMEI_Base64.replaceAll("\n", "");
632 | }
633 | catch(Exception e)
634 | {
635 | e.printStackTrace();
636 | }
637 | return IMEI_Base64;
638 | }
639 |
640 | private Cursor fetchTopFromDB(int limit)
641 | {
642 | String rawQuery = "SELECT * FROM cellRecords ORDER BY TIMESTAMP LIMIT " + limit;
643 | DBHandler dbHandler = new DBHandler(getApplicationContext());
644 | sqLiteDatabase = dbHandler.getWritableDatabase();
645 | return sqLiteDatabase.rawQuery(rawQuery, null);
646 | }
647 |
648 | public boolean isConnected()
649 | {
650 | ConnectivityManager connMgr =
651 | (ConnectivityManager) getSystemService(Activity.CONNECTIVITY_SERVICE);
652 | NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
653 | return networkInfo != null && networkInfo.isConnected();
654 | }
655 | }
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/HomeFragment.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.ActivityManager;
4 | import android.app.Fragment;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.SharedPreferences;
8 | import android.database.Cursor;
9 | import android.database.sqlite.SQLiteDatabase;
10 | import android.os.AsyncTask;
11 | import android.os.Bundle;
12 | import android.preference.PreferenceManager;
13 | import android.telephony.TelephonyManager;
14 | import android.util.Base64;
15 | import android.util.Log;
16 | import android.view.LayoutInflater;
17 | import android.view.Menu;
18 | import android.view.MenuInflater;
19 | import android.view.View;
20 | import android.view.ViewGroup;
21 | import android.widget.Button;
22 | import android.widget.TextView;
23 |
24 | import org.apache.http.HttpResponse;
25 | import org.apache.http.client.ClientProtocolException;
26 | import org.apache.http.client.HttpClient;
27 | import org.apache.http.client.methods.HttpGet;
28 | import org.apache.http.client.methods.HttpPost;
29 | import org.apache.http.entity.ByteArrayEntity;
30 | import org.apache.http.impl.client.DefaultHttpClient;
31 | import org.apache.http.util.EntityUtils;
32 | import org.json.JSONException;
33 | import org.json.JSONObject;
34 |
35 | import java.io.IOException;
36 | import java.net.URI;
37 | import java.net.URISyntaxException;
38 | import java.net.URLEncoder;
39 | import java.security.MessageDigest;
40 | import java.security.NoSuchAlgorithmException;
41 | import java.text.SimpleDateFormat;
42 | import java.util.Calendar;
43 | import java.util.Date;
44 | import java.util.TimeZone;
45 |
46 | import static edu.buffalo.cse.ubwins.cellmon.R.id.textView;
47 |
48 | /**
49 | * Created by pcoonan on 3/15/17.
50 | */
51 |
52 | public class HomeFragment extends Fragment implements View.OnClickListener {
53 |
54 | public final String TAG = "[CELNETMON-HOMEFRAG]";
55 |
56 | Button startTrackingButton;
57 | Button stopTrackingButton;
58 | SharedPreferences preferences;
59 | String URL_UPLOAD = "http://104.196.177.7:80/aggregator/upload/";
60 | String responsePhrase;
61 | String statusPhraseLogger;
62 | String recordsPhraseLogger;
63 | String IMEI_TO_POST;
64 |
65 | @Override
66 | public void onCreate(Bundle savedInstanceState){
67 | super.onCreate(savedInstanceState);
68 | setHasOptionsMenu(true);
69 | }
70 | @Override
71 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
72 | Bundle savedInstanceState){
73 | Log.d(TAG, "Creating Home Fragment view.");
74 | View view = inflater.inflate(R.layout.activity_main, container, false);
75 | preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
76 |
77 | startTrackingButton = (Button) view.findViewById(R.id.button4);
78 | stopTrackingButton = (Button) view.findViewById(R.id.button5);
79 |
80 | if(isMyServiceRunning(ForegroundService.class)){
81 | startTrackingButton.setEnabled(false);
82 | stopTrackingButton.setEnabled(true);
83 | }
84 | else{
85 | startTrackingButton.setEnabled(true);
86 | stopTrackingButton.setEnabled(false);
87 | }
88 |
89 | boolean isRegistered = preferences.getBoolean("isRegistered", false);
90 | TextView textView = (TextView) view.findViewById(R.id.textView30);
91 |
92 | if(isRegistered)
93 | {
94 | textView.setText("Device Already Registered!");
95 | }
96 | else
97 | {
98 | textView.setText("Device registration failed!");
99 | }
100 |
101 | startTrackingButton.setOnClickListener(this);
102 | stopTrackingButton.setOnClickListener(this);
103 |
104 | // Button forceUpload = (Button) view.findViewById(R.id.force_upload);
105 | // forceUpload.setOnClickListener(new View.OnClickListener() {
106 | // @Override
107 | // public void onClick(View v) {
108 | // Log.d(TAG, "Force Upload pressed");
109 | // new ForceExportTask().execute(URL_UPLOAD);
110 | // }
111 | // });
112 | //
113 | // Button forcePing = (Button) view.findViewById(R.id.ping);
114 | // forcePing.setOnClickListener(new View.OnClickListener() {
115 | // @Override
116 | // public void onClick(View v) {
117 | // new ForcePingTask().execute();
118 | // }
119 | // });
120 | //
121 | // Button mindate = (Button) view.findViewById(R.id.mindate);
122 | // mindate.setOnClickListener(new View.OnClickListener() {
123 | // @Override
124 | // public void onClick(View v) {
125 | // new MinDateTask().execute();
126 | // }
127 | // });
128 | return view;
129 | }
130 |
131 | @Override
132 | public void onClick(View v) {
133 | SharedPreferences.Editor editor = preferences.edit();
134 | Log.e(TAG, "inside on click");
135 | switch (v.getId()) {
136 | case R.id.button4:
137 | Intent startIntent = new Intent(getActivity(), ForegroundService.class);
138 | startIntent.setAction("startforeground");
139 | getActivity().startService(startIntent);
140 | editor.putBoolean("TRACKING", true);
141 | editor.commit();
142 | stopTrackingButton.setEnabled(true);
143 | startTrackingButton.setEnabled(false);
144 | break;
145 | case R.id.button5:
146 | if(isMyServiceRunning(ForegroundService.class))
147 | {
148 | Log.v("STOP Button","Stopped");
149 | Intent stopIntent = new Intent(getActivity(), ForegroundService.class);
150 | stopIntent.setAction("stopforeground");
151 | getActivity().startService(stopIntent);}
152 | startTrackingButton.setEnabled(true);
153 | stopTrackingButton.setEnabled(false);
154 | editor.putBoolean("TRACKING", false);
155 | editor.commit();
156 | break;
157 | default:
158 | break;
159 | }
160 | }
161 |
162 | private boolean isMyServiceRunning(Class> serviceClass) {
163 | ActivityManager manager = (ActivityManager) getActivity().getSystemService(Context.ACTIVITY_SERVICE);
164 | for (ActivityManager.RunningServiceInfo service :
165 | manager.getRunningServices(Integer.MAX_VALUE)) {
166 | if (serviceClass.getName().equals(service.service.getClassName())) {
167 | return true;
168 | }
169 | }
170 | return false;
171 | }
172 |
173 | @Override
174 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
175 | inflater.inflate(R.menu.home_menu, menu);
176 | super.onCreateOptionsMenu(menu, inflater);
177 | }
178 |
179 |
180 | class ForcePingTask extends AsyncTask{
181 |
182 | @Override
183 | protected String doInBackground(String... params) {
184 | String IMEI_HASH = "";
185 | String responseStr = "";
186 | try {
187 | /*HASH IMEI*/
188 | IMEI_HASH = genHash(getIMEI());
189 | } catch (NoSuchAlgorithmException e) {
190 | e.printStackTrace();
191 | }
192 | Log.v(TAG, "GENERATED IMEI HASH");
193 | //TODO KEEP-ALIVE GET
194 | HttpResponse response = null;
195 | try {
196 | HttpClient client = new DefaultHttpClient();
197 | HttpGet request = new HttpGet();
198 | String customURL = "http://104.196.177.7/aggregator/ping?imei_hash="
199 | + URLEncoder.encode(IMEI_HASH, "UTF-8");
200 | Log.d(TAG, customURL);
201 | request.setURI(new URI(customURL));
202 | response = client.execute(request);
203 | Log.v(TAG, "RESPONSE PHRASE FOR HTTP GET: "
204 | + response.getStatusLine().getReasonPhrase());
205 | Log.v(TAG, "RESPONSE STATUS FOR HTTP GET: "
206 | + response.getStatusLine().getStatusCode());
207 | responseStr = response.getStatusLine().getReasonPhrase();
208 | } catch (URISyntaxException e) {
209 | e.printStackTrace();
210 | } catch (ClientProtocolException e) {
211 | e.printStackTrace();
212 | } catch (IOException e) {
213 | e.printStackTrace();
214 | }
215 | return responseStr;
216 | }
217 | }
218 |
219 | class MinDateTask extends AsyncTask{
220 |
221 | @Override
222 | protected String doInBackground(String... params) {
223 | String IMEI_HASH = "";
224 | String responseStr = "";
225 | try {
226 | /*HASH IMEI*/
227 | IMEI_HASH = genHash(getIMEI());
228 | } catch (NoSuchAlgorithmException e) {
229 | e.printStackTrace();
230 | }
231 | Log.v(TAG, "GENERATED IMEI HASH");
232 | //TODO KEEP-ALIVE GET
233 | HttpResponse response = null;
234 | try {
235 | HttpClient client = new DefaultHttpClient();
236 | HttpGet request = new HttpGet();
237 | String customURL = "http://104.196.177.7/aggregator/mindate?imei_hash="
238 | + URLEncoder.encode(IMEI_HASH, "UTF-8");
239 | Log.d(TAG, customURL);
240 | request.setURI(new URI(customURL));
241 | response = client.execute(request);
242 | Log.v(TAG, "RESPONSE PHRASE FOR HTTP GET: "
243 | + response.getStatusLine().getReasonPhrase());
244 | Log.v(TAG, "RESPONSE STATUS FOR HTTP GET: "
245 | + response.getStatusLine().getStatusCode());
246 |
247 | responseStr = EntityUtils.toString(response.getEntity());
248 | Log.v(TAG, "RESPONSE" + responseStr);
249 |
250 | /*PARSE JSON RESPONSE*/
251 | JSONObject jsonObject = new JSONObject(responseStr);
252 | String time = jsonObject.getString("timestamp");
253 | // statusPhraseLogger = jsonObject.getString("status");
254 | Calendar cal = Calendar.getInstance();
255 | TimeZone tz = cal.getTimeZone();
256 |
257 | SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
258 | sdf.setTimeZone(tz);
259 |
260 | long timestamp = Long.parseLong(time);
261 | String parsed = sdf.format(new Date(timestamp));
262 | Log.d(TAG, "Mindate: " + parsed);
263 |
264 | } catch (URISyntaxException e) {
265 | e.printStackTrace();
266 | } catch (ClientProtocolException e) {
267 | e.printStackTrace();
268 | } catch (IOException e) {
269 | e.printStackTrace();
270 | } catch(JSONException e){
271 | e.printStackTrace();
272 | }
273 | return responseStr;
274 | }
275 | }
276 |
277 | class ForceExportTask extends AsyncTask{
278 | @Override
279 | protected String doInBackground(String... urls){
280 | Log.v(TAG, "inside ForceExportTask");
281 | return FORCE_POST(urls[0]);
282 | }
283 | }
284 |
285 | public String FORCE_POST(String url)
286 | {
287 | String TEMP_TAG = "[CURSOR_DATA] : ";
288 | int statusCode;
289 | String result = "";
290 |
291 | Cursor cursor = fetchTop12000FromDB();
292 | int count = cursor.getCount();
293 | DataRecordOuterClass.DataRecord.Builder dataRecord =
294 | DataRecordOuterClass.DataRecord.newBuilder();
295 | DataRecordOuterClass.DataRecord recordToSend;
296 |
297 |
298 | if (cursor.moveToFirst())
299 | {
300 | String IMEI = getIMEI();
301 | String networkOperatorCode = getNetworkOperatorCode();
302 | String networkOperatorName = getNetworkOperatorName();
303 |
304 | try{
305 | IMEI_TO_POST = genHash(IMEI);
306 | }
307 | catch(NoSuchAlgorithmException nsa)
308 | {
309 | nsa.printStackTrace();
310 | }
311 | dataRecord.setIMEIHASH(IMEI_TO_POST);
312 | dataRecord.setNETWORKOPERATORNAME(networkOperatorName);
313 | dataRecord.setNETWORKOPERATORCODE(networkOperatorCode);
314 |
315 | do {
316 | dataRecord.addENTRY(DataRecordOuterClass.DataEntry.newBuilder()
317 | .setFUSEDLAT(cursor.getDouble(1))
318 | .setFUSEDLONG(cursor.getDouble(2))
319 | .setSTALE(cursor.getInt(3) > 0)
320 | .setTIMESTAMP(cursor.getLong(4))
321 | .setNETWORKCELLTYPEValue(cursor.getInt(5))
322 | .setNETWORKTYPEValue(cursor.getInt(6))
323 | .setNETWORKPARAM1(cursor.getInt(7))
324 | .setNETWORKPARAM2(cursor.getInt(8))
325 | .setNETWORKPARAM3(cursor.getInt(9))
326 | .setNETWORKPARAM4(cursor.getInt(10))
327 | .setSIGNALDBM(cursor.getInt(11))
328 | .setSIGNALLEVEL(cursor.getInt(12))
329 | .setSIGNALASULEVEL(cursor.getInt(13))
330 | .setNETWORKSTATEValue(cursor.getInt(14))
331 | .setNETWORKDATAACTIVITYValue(cursor.getInt(15))
332 | .setVOICECALLSTATEValue(cursor.getInt(16)).build());
333 |
334 | recordToSend = dataRecord.build();
335 | } while (cursor.moveToNext());
336 |
337 | byte[] logToSend = recordToSend.toByteArray();
338 | int len = logToSend.length;
339 | Log.e("SIZE","Length of 5 entries is : "+len);
340 |
341 |
342 |
343 | try {
344 |
345 | /*1. create HttpClient*/
346 | HttpClient httpclient = new DefaultHttpClient();
347 |
348 | /*2. make POST request to the given URL*/
349 | HttpPost httpPost = new HttpPost(url);
350 |
351 | /*3. Build ByteArrayEntity*/
352 | ByteArrayEntity byteArrayEntity = new ByteArrayEntity(logToSend);
353 |
354 | /*4. Set httpPost Entity*/
355 | httpPost.setEntity(byteArrayEntity);
356 |
357 | /*5. Execute POST request to the given URL*/
358 | HttpResponse httpResponse = httpclient.execute(httpPost);
359 |
360 | /*9. receive response as inputStream*/
361 | statusCode = httpResponse.getStatusLine().getStatusCode();
362 |
363 | /*CONVERT INPUT STREAM TO STRING*/
364 | responsePhrase = EntityUtils.toString(httpResponse.getEntity());
365 | Log.v(TAG, "RESPONSE" + responsePhrase);
366 |
367 | /*PARSE JSON RESPONSE*/
368 | JSONObject jsonObject = new JSONObject(responsePhrase);
369 | recordsPhraseLogger = jsonObject.getString("records");
370 | statusPhraseLogger = jsonObject.getString("status");
371 |
372 | // Log.e(LOG_TAG, "STATUS: " + statusPhraseLogger);
373 | // Log.e(LOG_TAG, "RECORDS INSERTED: " + recordsPhraseLogger);
374 |
375 | /*DELETE FROM DB IF NO OF RECORDS FETCHED == NO OF RECORDS INSERTED*/
376 | if(Integer.parseInt(recordsPhraseLogger)==count)
377 | {
378 | Log.e(TAG, "Attempting to delete from DB");
379 | String rawQuery =
380 | "DELETE FROM cellRecords WHERE ID IN " +
381 | "(SELECT ID FROM cellRecords ORDER BY TIMESTAMP LIMIT " +
382 | count + ");";
383 | DBHandler dbHandler = new DBHandler(getActivity().getApplicationContext());
384 | SQLiteDatabase sqLiteDatabase = dbHandler.getWritableDatabase();
385 | sqLiteDatabase.beginTransaction();
386 | sqLiteDatabase.execSQL(rawQuery);
387 | sqLiteDatabase.setTransactionSuccessful();
388 | sqLiteDatabase.endTransaction();
389 | sqLiteDatabase.close();
390 | }
391 |
392 |
393 | if (statusCode != 404)
394 | {
395 | result = Integer.toString(statusCode);
396 | Log.v(TAG, "STATUS CODE: " + result);
397 | }
398 | else
399 | {
400 | result = Integer.toString(statusCode);
401 | Log.v(TAG, "STATUS CODE: " + result);
402 | }
403 | }
404 | catch (Exception e)
405 | {
406 | e.printStackTrace();
407 | }
408 | }
409 | else
410 | {
411 | Log.e(TEMP_TAG, "DB IS BROKE AS HELL!");
412 | result = "DB_EMPTY";
413 | }
414 | return result;
415 | }
416 |
417 | private String genHash(String input) throws NoSuchAlgorithmException
418 | {
419 | String IMEI_Base64="";
420 | try
421 | {
422 | MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
423 | byte[] sha256Hash = sha256.digest(input.getBytes("UTF-8"));
424 | IMEI_Base64 = Base64.encodeToString(sha256Hash, Base64.DEFAULT);
425 | IMEI_Base64=IMEI_Base64.replaceAll("\n", "");
426 | }
427 | catch(Exception e)
428 | {
429 | e.printStackTrace();
430 | }
431 | return IMEI_Base64;
432 | }
433 |
434 | private String getIMEI() {
435 | TelephonyManager telephonyManager =
436 | (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
437 | return telephonyManager.getDeviceId();
438 | }
439 |
440 | private String getNetworkOperatorCode() {
441 | TelephonyManager telephonyManager =
442 | (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
443 | return telephonyManager.getNetworkOperator();
444 | }
445 |
446 | private String getNetworkOperatorName() {
447 | TelephonyManager telephonyManager =
448 | (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
449 | return telephonyManager.getNetworkOperatorName();
450 | }
451 |
452 | private Cursor fetchTop12000FromDB()
453 | {
454 | String rawQuery = "SELECT * FROM cellRecords ORDER BY TIMESTAMP LIMIT 12000";
455 | DBHandler dbHandler = new DBHandler(getActivity().getApplicationContext());
456 | SQLiteDatabase sqLiteDatabase = dbHandler.getWritableDatabase();
457 | Cursor cursor = sqLiteDatabase.rawQuery(rawQuery, null);
458 | return cursor;
459 | }
460 | }
461 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/LocationFinder.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gautam on 6/18/16.
3 | * MBP111.0138.B16
4 | * agautam2@buffalo.edu
5 | * University at Buffalo, The State University of New York.
6 | * Copyright © 2016 Gautam. All rights reserved.
7 | */
8 |
9 | package edu.buffalo.cse.ubwins.cellmon;
10 |
11 | import android.app.Service;
12 | import android.content.Context;
13 | import android.content.Intent;
14 | import android.location.Location;
15 | import android.location.LocationListener;
16 | import android.location.LocationManager;
17 | import android.location.LocationProvider;
18 | import android.os.Bundle;
19 | import android.os.IBinder;
20 | import android.util.Log;
21 |
22 |
23 | public class LocationFinder extends Service implements LocationListener
24 | {
25 | private final Context mContext;
26 |
27 | public static double latitude;
28 | public static double longitude;
29 |
30 | // We want instant results once we start listening so we can minimize the amount of time
31 | // the gps is on
32 | private static final long distance = 0;
33 | private static final long updateInterval = 0;
34 | boolean isGPSEnabled = false;
35 | public static boolean isGPSUpdated = false;
36 | static final String TAG = "[CELNETMON-LOCFINDER]";
37 | protected LocationManager locationManager;
38 |
39 |
40 |
41 | public LocationFinder(Context context)
42 | {
43 | this.mContext = context;
44 | }
45 |
46 | public void getLocation()
47 | {
48 |
49 | locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
50 | isGPSEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
51 | if (isGPSEnabled)
52 | {
53 | try
54 | {
55 | locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, updateInterval, distance, this);
56 | }
57 | catch (SecurityException s)
58 | {
59 | s.printStackTrace();
60 | }
61 | }
62 | }
63 |
64 | public void stopUpdates(){
65 | locationManager = (LocationManager) mContext.getSystemService(LOCATION_SERVICE);
66 | locationManager.removeUpdates(this);
67 | }
68 |
69 | @Override
70 | public void onLocationChanged(Location location)
71 | {
72 | latitude = location.getLatitude();
73 | longitude = location.getLongitude();
74 | isGPSUpdated = true;
75 | stopUpdates();
76 | }
77 |
78 | @Override
79 | public void onProviderDisabled(String provider)
80 | {
81 | //Log.v(TAG,"inside Provider disabled");
82 | if (provider == LocationManager.GPS_PROVIDER){
83 | Log.v(TAG,"GPS Provider disabled by user");
84 | //can make toast here
85 | }
86 | else if(provider == LocationManager.NETWORK_PROVIDER){
87 | Log.v(TAG,"NETWORK Provider disabled by user");
88 |
89 | //can make toast here
90 | }
91 | }
92 |
93 | @Override
94 | public void onProviderEnabled(String provider)
95 | {
96 | //Log.v(TAG,"inside Provider enabled");
97 | if (provider == LocationManager.GPS_PROVIDER){
98 | Log.v(TAG,"GPS Provider enabled by user");
99 |
100 | //can make toast here
101 | }
102 | else if(provider == LocationManager.NETWORK_PROVIDER){
103 | Log.v(TAG,"NETWORK Provider enabled by user");
104 |
105 | //can make toast here
106 | }
107 | }
108 |
109 | @Override
110 | public void onStatusChanged(String provider, int status, Bundle extras)
111 | {
112 | //Log.v(TAG,"inside Provider status changed");
113 | if (provider == LocationManager.GPS_PROVIDER)
114 | {
115 | Log.v(TAG,"GPS Provider status changed");
116 | if(status == LocationProvider.OUT_OF_SERVICE){
117 | Log.v(TAG,"GPS Provider has gone out of service");
118 | }
119 | else if(status == LocationProvider.TEMPORARILY_UNAVAILABLE){
120 | Log.v(TAG,"GPS Provider is temporarily unavailable");
121 | }
122 | else if (status == LocationProvider.AVAILABLE){
123 | Log.v(TAG,"GPS Provider is available again");
124 | }
125 |
126 | }
127 | else if(provider == LocationManager.NETWORK_PROVIDER){
128 | Log.v(TAG,"Network Provider status changed");
129 | if(status == LocationProvider.OUT_OF_SERVICE){
130 | Log.v(TAG,"Network Provider has gone out of service");
131 | }
132 | else if(status == LocationProvider.TEMPORARILY_UNAVAILABLE){
133 | Log.v(TAG,"Network Provider is temporarily unavailable");
134 | }
135 | else if (status == LocationProvider.AVAILABLE){
136 | Log.v(TAG,"Network Provider is available again");
137 | }
138 |
139 | }
140 | }
141 |
142 | @Override
143 | public IBinder onBind(Intent arg0)
144 | {
145 | return null;
146 | }
147 |
148 | }
149 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/MainActivity.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gautam on 6/18/16.
3 | * MBP111.0138.B16
4 | * agautam2@buffalo.edu
5 | * University at Buffalo, The State University of New York.
6 | * Copyright © 2016 Gautam. All rights reserved.
7 | *
8 | * CelNetMon v1.0 ~ gets location pure network based location does not fail to GPS
9 | * CelNetMon v1.1 ~ registers device uses a JSON POST
10 | * CelNetMon v1.2 ~ with user permissions for android v6.0+, records DataActivity and DataSate, logs call state
11 | * CelNetMon v1.2.1 ~ with alarm and periodic recording on 60 secs.
12 | * CelNetMon v1.2.2 ~ Permissions handled on onCreate in MainActivity. GPS functionality included. Records data even when location object returns null.
13 | * CelNetMon v1.3 ~ Uses ScheduledExecutorService, does not uses Alarm(removed), does not uses Handler(removed), Uses wake lock.
14 | * CelNetMon v1.3.1 ~ New Registration Fields Added. Now a total of 19 fields in the registration POST.
15 | * CelNetMon v1.3.2 ~ Registration fields total of 18. HTTP POST via building ByteArrayEntity. Protocol Buffers tested.
16 | * CelNetMon v1.3.3 ~ SALT(SharedPref) and HASH(SHA256) functionality added and tested. Minor Layout Change. Toast Messages Changed.
17 | * CelNetMon v1.4.0 ~ Automated Registration. Splash Screen Added.
18 | * CelNetMon v1.4.1 ~ BETA v1 : Uploading on wifi and charging in foreground, button changes,
19 | */
20 |
21 | package edu.buffalo.cse.ubwins.cellmon;
22 |
23 | import android.Manifest;
24 | import android.app.Activity;
25 | import android.app.Fragment;
26 | import android.app.FragmentManager;
27 | import android.content.Context;
28 | import android.content.Intent;
29 | import android.content.IntentFilter;
30 | import android.content.SharedPreferences;
31 | import android.content.pm.PackageManager;
32 | import android.content.res.Configuration;
33 | import android.database.Cursor;
34 | import android.database.sqlite.SQLiteDatabase;
35 | import android.net.ConnectivityManager;
36 | import android.net.NetworkInfo;
37 | import android.os.AsyncTask;
38 | import android.os.Build;
39 | import android.preference.PreferenceManager;
40 | import android.support.annotation.NonNull;
41 | import android.support.v4.app.ActivityCompat;
42 | import android.support.v4.view.GravityCompat;
43 | import android.support.v4.widget.DrawerLayout;
44 | import android.support.v7.app.ActionBarDrawerToggle;
45 | import android.support.v7.app.AppCompatActivity;
46 | import android.os.Bundle;
47 | import android.support.v7.widget.Toolbar;
48 | import android.telephony.TelephonyManager;
49 | import android.util.Log;
50 | import android.view.Menu;
51 | import android.view.MenuInflater;
52 | import android.view.MenuItem;
53 | import android.view.View;
54 | import android.widget.AdapterView;
55 | import android.widget.ArrayAdapter;
56 | import android.widget.Button;
57 | import android.widget.ListView;
58 | import android.widget.TextView;
59 | import android.widget.Toast;
60 | import android.support.design.widget.Snackbar;
61 |
62 | import org.apache.http.client.ClientProtocolException;
63 | import org.apache.http.client.methods.HttpGet;
64 | import org.apache.http.entity.ByteArrayEntity;
65 | import org.apache.http.util.EntityUtils;
66 | import org.json.JSONException;
67 | import org.json.JSONObject;
68 | import java.io.File;
69 | import java.io.IOException;
70 | import java.io.InputStream;
71 | import org.apache.http.HttpResponse;
72 | import org.apache.http.client.HttpClient;
73 | import org.apache.http.client.methods.HttpPost;
74 | import org.apache.http.impl.client.DefaultHttpClient;
75 |
76 | import java.net.URI;
77 | import java.net.URISyntaxException;
78 | import java.net.URLEncoder;
79 | import java.security.MessageDigest;
80 | import java.security.NoSuchAlgorithmException;
81 | import android.util.Base64;
82 | import android.app.ActivityManager;
83 |
84 | import com.facebook.stetho.Stetho;
85 | //import com.pushlink.android.PushLink;
86 |
87 | public class MainActivity extends AppCompatActivity implements
88 | ActivityCompat.OnRequestPermissionsResultCallback
89 | {
90 |
91 | public final String TAG = "[CELNETMON-ACTIVITY]";
92 | private DrawerLayout mLayout;
93 | private static final int REQUEST_LOCATION = 0;
94 | private static final int REQUEST_STORAGE = 2;
95 | private static final int REQUEST_PHONE = 1;
96 | private static final int REQUEST_WAKELOCK = 3;
97 | String URL = "http://104.196.177.7:80/aggregator/register/";
98 | String fileName = "device_registration_details";
99 | File file;
100 | String responsePhrase;
101 | String reasonPhrase;
102 | JSONObject jsonObject;
103 | String statusPhrase;
104 | String IMEI_TO_POST;
105 | NetworkStateReceiver receiver;
106 | SharedPreferences preferences;
107 | String URL_UPLOAD = "http://104.196.177.7:80/aggregator/upload/";
108 |
109 | private String[] actions;
110 | // private DrawerLayout mDrawerLayout;
111 | private ListView mDrawerList;
112 | private CharSequence mTitle;
113 | private CharSequence mDrawerTitle;
114 | private ActionBarDrawerToggle mDrawerToggle;
115 |
116 | @Override
117 | protected void onCreate(Bundle savedInstanceState)
118 | {
119 | preferences = PreferenceManager.getDefaultSharedPreferences(this);
120 |
121 | super.onCreate(savedInstanceState);
122 | setContentView(R.layout.activity_base);
123 |
124 |
125 | // Initialize Stetho to allow for viewing database in the Chrome inspector
126 | Stetho.initialize(Stetho.newInitializerBuilder(this)
127 | .enableDumpapp(
128 | Stetho.defaultDumperPluginsProvider(this)
129 | ).enableWebKitInspector(
130 | Stetho.defaultInspectorModulesProvider(this)
131 | ).build());
132 |
133 | // Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
134 | // setSupportActionBar(mToolbar);
135 |
136 | file = new File(getApplicationContext().getFilesDir(), fileName);
137 |
138 | /*DECLARE EDITOR FOR PERMISSIONS */
139 | SharedPreferences.Editor editor = preferences.edit();
140 |
141 | /*First read location permission*/
142 | if (ActivityCompat.checkSelfPermission(getApplicationContext(),
143 | Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
144 | {
145 | requestLocationPermission();
146 | }
147 | else
148 | {
149 | editor.putBoolean("LOCATION", true);
150 | editor.commit();
151 | }
152 |
153 | /*Second read phone state permission*/
154 | if (ActivityCompat.checkSelfPermission(getApplicationContext(),
155 | Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED)
156 | {
157 | requestPhonePermission();
158 | }
159 | else
160 | {
161 | editor.putBoolean("PHONE", true);
162 | editor.commit();
163 | }
164 |
165 | /*Write to Storage permission*/
166 | if (ActivityCompat.checkSelfPermission(getApplicationContext(),
167 | Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
168 | {
169 | requestStoragePermission();
170 | }
171 | else
172 | {
173 | editor.putBoolean("STORAGE", true);
174 | editor.commit();
175 | }
176 |
177 | /*Wake Lock Permission*/
178 |
179 | if (ActivityCompat.checkSelfPermission(getApplicationContext(),
180 | Manifest.permission.WAKE_LOCK) != PackageManager.PERMISSION_GRANTED)
181 | {
182 | requestWakeLockPermission();
183 | }
184 | else
185 | {
186 | editor.putBoolean("WAKELOCK", true);
187 | editor.commit();
188 | }
189 |
190 | /* CALL TO REGISTER DEVICE*/
191 | /*FETCH ALL CONDITIONS TO CHECK FROM SHAREDPREF*/
192 | boolean locPermission = preferences.getBoolean("LOCATION",false);
193 | boolean storagePermission = preferences.getBoolean("STORAGE",false);
194 | boolean phonePermission = preferences.getBoolean("PHONE",false);
195 | boolean isRegistered = preferences.getBoolean("isRegistered", false);
196 |
197 | /*Call only after all 3 permissions are granted*/
198 | if(!isRegistered && locPermission && storagePermission && phonePermission)
199 | {
200 | onRegisterClicked();
201 | }
202 |
203 | Log.v(TAG, "CelNetMon Service Started");
204 |
205 |
206 | // Set up UI
207 |
208 | mTitle = mDrawerTitle = getTitle();
209 | actions = getResources().getStringArray(R.array.app_actions);
210 | mLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
211 | mDrawerList = (ListView) findViewById(R.id.left_drawer);
212 | Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
213 | setSupportActionBar(mToolbar);
214 |
215 | mLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
216 |
217 | mDrawerList.setAdapter(new ArrayAdapter(this,
218 | R.layout.simple_list_item, actions));
219 |
220 | mDrawerList.setOnItemClickListener(new DrawerClickListener());
221 |
222 |
223 |
224 | mDrawerToggle = new ActionBarDrawerToggle(
225 | this,
226 | mLayout,
227 | R.string.navigation_drawer_open,
228 | R.string.navigation_drawer_close
229 | ) {
230 | public void onDrawerClosed(View view){
231 | super.onDrawerClosed(view);
232 | getSupportActionBar().setTitle(mTitle);
233 | invalidateOptionsMenu();
234 | }
235 |
236 | public void onDrawerOpened(View drawerView){
237 | super.onDrawerOpened(drawerView);
238 | getSupportActionBar().setTitle("Options");
239 | invalidateOptionsMenu();
240 | }
241 | };
242 | mDrawerToggle.setDrawerIndicatorEnabled(true);
243 | mLayout.addDrawerListener(mDrawerToggle);
244 |
245 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
246 | getSupportActionBar().setHomeButtonEnabled(true);
247 |
248 | if(savedInstanceState == null){
249 | selectItem(0);
250 | }
251 |
252 | }
253 |
254 | @Override
255 | protected void onPostCreate(Bundle savedInstanceState){
256 | super.onPostCreate(savedInstanceState);
257 | mDrawerToggle.syncState();
258 | }
259 |
260 | @Override
261 | public void onConfigurationChanged(Configuration newConfig){
262 | super.onConfigurationChanged(newConfig);
263 | mDrawerToggle.onConfigurationChanged(newConfig);
264 | }
265 |
266 | @Override
267 | public boolean onCreateOptionsMenu(Menu menu) {
268 | getMenuInflater().inflate(R.menu.app_menu,menu);
269 | return true;
270 | }
271 |
272 | @Override
273 | public boolean onOptionsItemSelected(MenuItem item) {
274 | if(mDrawerToggle.onOptionsItemSelected(item)){
275 | return true;
276 | }
277 |
278 | return super.onOptionsItemSelected(item);
279 | }
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 | public void requestLocationPermission() {
292 | ActivityCompat.requestPermissions(this,
293 | new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_LOCATION);
294 | }
295 |
296 | public void requestPhonePermission() {
297 | ActivityCompat.requestPermissions(this,
298 | new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_PHONE);
299 | }
300 |
301 | public void requestStoragePermission() {
302 | ActivityCompat.requestPermissions(this,
303 | new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_STORAGE);
304 | }
305 |
306 | public void requestWakeLockPermission() {
307 | ActivityCompat.requestPermissions(this,
308 | new String[]{Manifest.permission.WAKE_LOCK}, REQUEST_WAKELOCK);
309 | }
310 |
311 | @Override
312 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
313 | @NonNull int[] grantResults) {
314 | SharedPreferences.Editor editor = preferences.edit();
315 | if (requestCode == REQUEST_LOCATION) {
316 | /*Check if the only required permission has been granted*/
317 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
318 | //Log.i(TAG, "Location permission has now been granted.");
319 | Snackbar.make(mLayout, R.string.permission_available_location,
320 | Snackbar.LENGTH_SHORT).show();
321 | editor.putBoolean("LOCATION", true);
322 | editor.commit();
323 | boolean one = preferences.getBoolean("STORAGE", false);
324 | boolean two = preferences.getBoolean("PHONE", false);
325 | boolean isRegistered = preferences.getBoolean("isRegistered", false);
326 | if(one && two && !isRegistered)
327 | {
328 | onRegisterClicked();
329 | }
330 | }
331 | else {
332 | Snackbar.make(mLayout, R.string.permissions_not_granted,
333 | Snackbar.LENGTH_SHORT).show();
334 | }
335 | }
336 | else if (requestCode == REQUEST_STORAGE) {
337 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
338 | Snackbar.make(mLayout, R.string.permission_available_storage,
339 | Snackbar.LENGTH_SHORT).show();
340 | editor.putBoolean("STORAGE", true);
341 | editor.commit();
342 | boolean one = preferences.getBoolean("LOCATION", false);
343 | boolean two = preferences.getBoolean("PHONE", false);
344 | boolean isRegistered = preferences.getBoolean("isRegistered", false);
345 | if(one && two && !isRegistered)
346 | {
347 | onRegisterClicked();
348 | }
349 | }
350 | else {
351 | Snackbar.make(mLayout, R.string.permissions_not_granted,
352 | Snackbar.LENGTH_SHORT).show();
353 | }
354 | }
355 | else if (requestCode == REQUEST_PHONE) {
356 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
357 | Snackbar.make(mLayout, R.string.permission_available_phone,
358 | Snackbar.LENGTH_SHORT).show();
359 | editor.putBoolean("PHONE", true);
360 | editor.commit();
361 | boolean one = preferences.getBoolean("LOCATION", false);
362 | boolean two = preferences.getBoolean("STORAGE", false);
363 | boolean isRegistered = preferences.getBoolean("isRegistered", false);
364 | if(one && two && !isRegistered)
365 | {
366 | onRegisterClicked();
367 | }
368 | } else {
369 | Snackbar.make(mLayout, R.string.permissions_not_granted,
370 | Snackbar.LENGTH_SHORT).show();
371 | }
372 | }
373 | else if (requestCode == REQUEST_WAKELOCK) {
374 | if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
375 | Snackbar.make(mLayout, R.string.permission_available_wakelock,
376 | Snackbar.LENGTH_SHORT).show();
377 | editor.putBoolean("WAKELOCK", true);
378 | editor.commit();
379 | }
380 | else {
381 | Snackbar.make(mLayout, R.string.permissions_not_granted,
382 | Snackbar.LENGTH_SHORT).show();
383 | }
384 | }
385 | else {
386 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
387 | }
388 | }
389 |
390 | /*Methods to get registration fields*/
391 | /* https://developer.android.com/reference/android/os/Build.html */
392 |
393 |
394 | private String getIMEI() {
395 | TelephonyManager telephonyManager =
396 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
397 | return telephonyManager.getDeviceId();
398 | }
399 |
400 | private String getBoard() { return Build.BOARD; }
401 | private String getBrand() { return Build.BRAND; }
402 | private String getDevice() { return Build.DEVICE; }
403 | private String getHardware() { return android.os.Build.HARDWARE; }
404 | private String getManufacturer() { return android.os.Build.MANUFACTURER; }
405 | private String getModel() { return android.os.Build.MODEL; }
406 | private String getProduct() { return Build.PRODUCT; }
407 |
408 | /* https://developer.android.com/reference/android/telephony/TelephonyManager.html */
409 |
410 | private String getNetworkCountryISO() {
411 | TelephonyManager telephonyManager =
412 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
413 | return telephonyManager.getNetworkCountryIso();
414 | }
415 |
416 | private String getNetworkOperatorCode() {
417 | TelephonyManager telephonyManager =
418 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
419 | return telephonyManager.getNetworkOperator();
420 | }
421 |
422 | private String getNetworkOperatorName() {
423 | TelephonyManager telephonyManager =
424 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
425 | return telephonyManager.getNetworkOperatorName();
426 | }
427 |
428 | private String getPhoneType() {
429 | TelephonyManager telephonyManager =
430 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
431 | return Integer.toString(telephonyManager.getPhoneType());
432 | }
433 |
434 | private String getSimCountryISO() {
435 | TelephonyManager telephonyManager =
436 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
437 | return telephonyManager.getSimCountryIso();
438 | }
439 |
440 | private String getSimOperator() {
441 | TelephonyManager telephonyManager =
442 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
443 | return telephonyManager.getSimOperator();
444 | }
445 |
446 | private String getSimOperatorName() {
447 | TelephonyManager telephonyManager =
448 | (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
449 | return telephonyManager.getSimOperatorName();
450 | }
451 |
452 | /* https://developer.android.com/reference/android/os/Build.VERSION.html */
453 | //private String getBaseOS(){return Build.VERSION.BASE_OS;}
454 |
455 | private String getRelease() { return Build.VERSION.RELEASE; }
456 | private String getSdkInt() { return Integer.toString(Build.VERSION.SDK_INT); }
457 |
458 | public boolean isConnected()
459 | {
460 | ConnectivityManager connMgr =
461 | (ConnectivityManager) getSystemService(Activity.CONNECTIVITY_SERVICE);
462 | NetworkInfo networkInfo = connMgr.getActiveNetworkInfo();
463 | return networkInfo != null && networkInfo.isConnected();
464 | }
465 |
466 |
467 | public String POST(String url)
468 | {
469 | Log.d(TAG, "Registering device...");
470 |
471 | InputStream inputStream = null;
472 | int statusCode;
473 | String result = "";
474 |
475 | try {
476 |
477 | String IMEI = getIMEI();
478 | IMEI_TO_POST = genHash(IMEI);
479 |
480 |
481 | /*FETCH OTHER PARAMS*/
482 | String board = getBoard();
483 | String brand = getBrand();
484 | String device = getDevice();
485 | String hardware = getHardware();
486 | String manufacturer = getManufacturer();
487 | String modelMake = getModel();
488 | String product = getProduct();
489 |
490 | String networkCountryISO = getNetworkCountryISO();
491 | String networkOperatorCode = getNetworkOperatorCode();
492 | String networkOperatorName = getNetworkOperatorName();
493 | String phoneType = getPhoneType();
494 | String simCountryISO = getSimCountryISO();
495 | String simOperator = getSimOperator();
496 | String simOperatorName = getSimOperatorName();
497 |
498 | String release = getRelease();
499 | String sdkInt = getSdkInt();
500 |
501 | /*SERIALIZATION*/
502 | RegisterDeviceOuterClass.RegisterDevice registerDevice =
503 | RegisterDeviceOuterClass.RegisterDevice.newBuilder()
504 | .setIMEIHASH(IMEI_TO_POST)
505 | .setBOARD(board)
506 | .setBRAND(brand)
507 | .setDEVICE(device)
508 | .setHARDWARE(hardware)
509 | .setMANUFACTURER(manufacturer)
510 | .setMODEL(modelMake)
511 | .setPRODUCT(product)
512 | .setNETWORKCOUNTRYISO(networkCountryISO)
513 | .setNETWORKOPERATORCODE(networkOperatorCode)
514 | .setNETWORKOPERATORNAME(networkOperatorName)
515 | .setPHONETYPE(phoneType)
516 | .setSIMCOUNTRYISO(simCountryISO)
517 | .setSIMOPERATOR(simOperator)
518 | .setSIMOPERATORNAME(simOperatorName)
519 | .setRELEASE(release)
520 | .setSDKINT(sdkInt).build();
521 |
522 | byte infoToSend[] = registerDevice.toByteArray();
523 |
524 | /*1. create HttpClient*/
525 | HttpClient httpclient = new DefaultHttpClient();
526 |
527 | /*2. make POST request to the given URL*/
528 | HttpPost httpPost = new HttpPost(url);
529 |
530 | /*5. Build ByteArrayEntity*/
531 | //StringEntity se = new StringEntity(json);
532 | ByteArrayEntity byteArrayEntity = new ByteArrayEntity(infoToSend);
533 |
534 | /*6. Set httpPost Entity*/
535 | httpPost.setEntity(byteArrayEntity);
536 | //httpPost.setEntity(inputStreamEntity);
537 |
538 | /*7. Set some headers to inform server about the type of the content*/
539 | //httpPost.setHeader("Accept", "application/json");
540 | //httpPost.setHeader("Content-type", "application/json");
541 |
542 | /*8. Execute POST request to the given URL*/
543 | HttpResponse httpResponse = httpclient.execute(httpPost);
544 |
545 | /*9. receive response as inputStream*/
546 | statusCode = httpResponse.getStatusLine().getStatusCode();
547 |
548 | /*CONVERT INPUT STREAM TO STRING*/
549 | responsePhrase = EntityUtils.toString(httpResponse.getEntity());
550 | Log.v(TAG, "RESPONSE" + responsePhrase);
551 | Log.d(TAG, httpResponse.toString());
552 | /*PARSE JSON RESPONSE*/
553 |
554 | if(statusCode!=404)
555 | {
556 | result = Integer.toString(statusCode);
557 | Log.v(TAG, "STATUS CODE: " + result);
558 | }
559 | else
560 | {
561 | result = Integer.toString(statusCode);
562 | //Log.v(TAG, "STATUS CODE: " + result);
563 | }
564 | }
565 | catch (Exception e)
566 | {
567 | Log.d("InputStream", e.getLocalizedMessage());
568 | }
569 | return result;
570 | }
571 |
572 | public void onRegisterClicked()
573 | {
574 | boolean isConnected = isConnected();
575 | boolean isRegistered = preferences.getBoolean("isRegistered", false);
576 | if (isConnected && !isRegistered)
577 | {
578 | new HttpAsyncTask().execute(URL);
579 | }
580 | else
581 | {
582 | Log.v(TAG, "isConnected = FALSE");
583 | Toast.makeText(getBaseContext(),
584 | "Device has no Internet Connectivity! " +
585 | "Please check your Network Connection and try again",
586 | Toast.LENGTH_LONG).show();
587 |
588 | if(!isRegistered)
589 | {
590 |
591 | receiver = new NetworkStateReceiver();
592 | receiver.addListener(new NetworkStateReceiver.NetworkStateReceiverListener() {
593 | @Override
594 | public void networkAvailable() {
595 | onRegisterClicked();
596 | }
597 |
598 | @Override
599 | public void networkUnavailable() {
600 | //Log.v("AUTOMATE", "NETWORK IS UNAVAILABLE");
601 | }
602 | });
603 | registerReceiver(receiver,new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
604 | }
605 | }
606 | }
607 |
608 |
609 | private class HttpAsyncTask extends AsyncTask
610 | {
611 | @Override
612 | protected String doInBackground(String... urls)
613 | {
614 | return POST(urls[0]);
615 | }
616 | @Override
617 | protected void onPostExecute(String result)
618 | {
619 | try {
620 | jsonObject = new JSONObject(responsePhrase);
621 | statusPhrase = jsonObject.getString("status");
622 | }
623 | catch (JSONException j)
624 | {
625 | j.printStackTrace();
626 | }
627 |
628 | if(statusPhrase!=null && statusPhrase.equals("SUCCESS"))
629 | {
630 | TextView textView = (TextView) findViewById(R.id.textView30);
631 | if(textView != null) textView.setText("Device Registered!");
632 | SharedPreferences.Editor editor = preferences.edit();
633 | editor.putBoolean("isRegistered", true);
634 | editor.commit();
635 | boolean temp = preferences.getBoolean("isRegistered", false);
636 | Log.e(TAG, "isRegistered value [temp]: " + temp);
637 | }
638 | else if(statusPhrase!=null && statusPhrase.equals("FAIL"))
639 | {
640 | try {
641 | reasonPhrase = jsonObject.getString("reason");
642 | }
643 | catch (JSONException j)
644 | {
645 | j.printStackTrace();
646 | }
647 | if(reasonPhrase.equals("Given IMEI_HASH configuration already exists"))
648 | {
649 | TextView textView = (TextView) findViewById(R.id.textView30);
650 | if(textView != null) textView.setText("Device Already Registered!");
651 | SharedPreferences.Editor editor = preferences.edit();
652 | editor.putBoolean("isRegistered", true);
653 | editor.commit();
654 | }
655 | else
656 | {
657 | Log.d(TAG, reasonPhrase);
658 | TextView textView = (TextView) findViewById(R.id.textView30);
659 | if(textView != null) textView.setText("Device Registration Failed!");
660 | }
661 | }
662 | }
663 | }
664 |
665 | private String genHash(String input) throws NoSuchAlgorithmException
666 | {
667 | String IMEI_Base64="";
668 | try
669 | {
670 | MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
671 | byte[] sha256Hash = sha256.digest(input.getBytes("UTF-8"));
672 | IMEI_Base64 = Base64.encodeToString(sha256Hash, Base64.DEFAULT);
673 | IMEI_Base64=IMEI_Base64.replaceAll("\n", "");
674 | }
675 | catch(Exception e)
676 | {
677 | e.printStackTrace();
678 | }
679 | return IMEI_Base64;
680 | }
681 |
682 | private class DrawerClickListener implements android.widget.AdapterView.OnItemClickListener {
683 | @Override
684 | public void onItemClick(AdapterView> parent, View view, int position, long id) {
685 | Log.d(TAG,"ID selected: " + id);
686 | Log.d(TAG, "ID for Home: " + R.string.app_menu_home);
687 | selectItem(position);
688 | }
689 | }
690 |
691 | private void selectItem(int position){
692 | Fragment fragment;
693 | switch (position){
694 | case 0:
695 | fragment = new HomeFragment();
696 | break;
697 | case 1:
698 | fragment = new MapFragment();
699 | break;
700 | default:
701 | fragment = new HomeFragment();
702 | }
703 | FragmentManager fragmentManager = getFragmentManager();
704 | fragmentManager.beginTransaction()
705 | .replace(R.id.content_frame, fragment)
706 | .commit();
707 |
708 | mDrawerList.setItemChecked(position, true);
709 | setTitle(actions[position]);
710 | mLayout.closeDrawers();
711 | }
712 |
713 | @Override
714 | public void setTitle(CharSequence title){
715 | mTitle = title;
716 | getSupportActionBar().setTitle(mTitle);
717 | }
718 | }
719 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/MapFragment.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.DatePickerDialog;
4 | import android.app.Fragment;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.database.DatabaseUtils;
8 | import android.database.sqlite.SQLiteDatabase;
9 | import android.os.AsyncTask;
10 | import android.os.Bundle;
11 | import android.telephony.TelephonyManager;
12 | import android.util.Base64;
13 | import android.util.Log;
14 | import android.view.LayoutInflater;
15 | import android.view.Menu;
16 | import android.view.MenuInflater;
17 | import android.view.MenuItem;
18 | import android.view.View;
19 | import android.view.ViewGroup;
20 | import android.widget.DatePicker;
21 | import android.widget.Toast;
22 |
23 | import com.google.android.gms.maps.CameraUpdateFactory;
24 | import com.google.android.gms.maps.GoogleMap;
25 | import com.google.android.gms.maps.MapView;
26 | import com.google.android.gms.maps.MapsInitializer;
27 | import com.google.android.gms.maps.OnMapReadyCallback;
28 | import com.google.android.gms.maps.model.BitmapDescriptor;
29 | import com.google.android.gms.maps.model.BitmapDescriptorFactory;
30 | import com.google.android.gms.maps.model.CameraPosition;
31 | import com.google.android.gms.maps.model.LatLng;
32 | import com.google.android.gms.maps.model.MarkerOptions;
33 | import com.google.maps.android.clustering.ClusterManager;
34 |
35 | import org.apache.http.HttpResponse;
36 | import org.apache.http.NameValuePair;
37 | import org.apache.http.client.ClientProtocolException;
38 | import org.apache.http.client.HttpClient;
39 | import org.apache.http.client.methods.HttpGet;
40 | import org.apache.http.client.utils.URLEncodedUtils;
41 | import org.apache.http.impl.client.DefaultHttpClient;
42 | import org.apache.http.message.BasicNameValuePair;
43 | import org.apache.http.util.EntityUtils;
44 | import org.json.JSONArray;
45 | import org.json.JSONException;
46 | import org.json.JSONObject;
47 | import org.json.JSONStringer;
48 |
49 | import java.io.IOException;
50 | import java.lang.reflect.Array;
51 | import java.net.URI;
52 | import java.net.URISyntaxException;
53 | import java.net.URLEncoder;
54 | import java.security.MessageDigest;
55 | import java.security.NoSuchAlgorithmException;
56 | import java.text.ParseException;
57 | import java.text.SimpleDateFormat;
58 | import java.util.ArrayList;
59 | import java.util.Calendar;
60 | import java.util.Date;
61 | import java.util.LinkedList;
62 | import java.util.List;
63 | import java.util.TimeZone;
64 |
65 | import static android.R.attr.data;
66 | import static android.R.attr.fragment;
67 | import static android.os.Build.VERSION_CODES.M;
68 | import static com.facebook.stetho.inspector.network.PrettyPrinterDisplayType.JSON;
69 |
70 | import static edu.buffalo.cse.ubwins.cellmon.LocationFinder.longitude;
71 |
72 | /**
73 | * Created by pcoonan on 3/15/17.
74 | */
75 |
76 | public class MapFragment extends Fragment implements DateSelectedListener {
77 | public final String TAG = "[CELNETMON-MAPFRAG]";
78 |
79 | MapView mMapView;
80 | private GoogleMap googleMap;
81 | private float[] colorMap = { 0.0f, 30.0f, 60.0f, 90.0f, 120.0f };
82 | private String[] networkTypeMap = { "GSM", "CDMA", "LTE", "WCDMA" };
83 | private Long mindate;
84 |
85 | public MapFragment(){
86 | setHasOptionsMenu(true);
87 | }
88 |
89 | @Override
90 | public void onCreate(Bundle savedInstanceState){
91 | super.onCreate(savedInstanceState);
92 | new MinDateTask().execute("start");
93 | setHasOptionsMenu(true);
94 | }
95 | @Override
96 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
97 | View rootView = inflater.inflate(R.layout.location_fragment, container, false);
98 |
99 | mMapView = (MapView) rootView.findViewById(R.id.mapView);
100 | mMapView.onCreate(savedInstanceState);
101 |
102 | mMapView.onResume(); // needed to get the map to display immediately
103 |
104 | try {
105 | MapsInitializer.initialize(getActivity().getApplicationContext());
106 | } catch (Exception e) {
107 | e.printStackTrace();
108 | }
109 |
110 | mMapView.getMapAsync(new OnMapReadyCallback() {
111 | @Override
112 | public void onMapReady(GoogleMap mMap) {
113 | googleMap = mMap;
114 | refreshMap(null);
115 | }
116 | });
117 |
118 | return rootView;
119 | }
120 |
121 |
122 |
123 |
124 | @Override
125 | public void onResume() {
126 | super.onResume();
127 | mMapView.onResume();
128 | }
129 |
130 | @Override
131 | public void onPause() {
132 | super.onPause();
133 | mMapView.onPause();
134 | }
135 |
136 | @Override
137 | public void onDestroy() {
138 | super.onDestroy();
139 | mMapView.onDestroy();
140 | }
141 |
142 | @Override
143 | public void onLowMemory() {
144 | super.onLowMemory();
145 | mMapView.onLowMemory();
146 | }
147 |
148 | @Override
149 | public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
150 | inflater.inflate(R.menu.map_menu, menu);
151 | super.onCreateOptionsMenu(menu, inflater);
152 | }
153 |
154 | @Override
155 | public boolean onOptionsItemSelected(MenuItem item) {
156 | switch (item.getItemId()){
157 | case R.id.day_select:
158 | Log.d(TAG, "Day selected");
159 | if(!item.isChecked()) item.setChecked(true);
160 | new MinDateTask().execute("day");
161 | return true;
162 | case R.id.week_select:
163 | Log.d(TAG, "Week selected");
164 | if(!item.isChecked()) item.setChecked(true);
165 |
166 | new MinDateTask().execute("week");
167 | return true;
168 | case R.id.month_select:
169 | Log.d(TAG, "Month selected");
170 | if(!item.isChecked()) item.setChecked(true);
171 | new MinDateTask().execute("month");
172 | return true;
173 | default:
174 | Log.d(TAG, "Other selected");
175 | return super.onOptionsItemSelected(item);
176 | }
177 | }
178 |
179 | @Override
180 | public void onFinishSelect(String type, String value) {
181 | Log.d(TAG, type + " " + value);
182 | Calendar minDate = Calendar.getInstance();
183 | SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
184 | sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
185 | try{
186 | minDate.setTime(sdf.parse(value));
187 | }
188 | catch(ParseException e){
189 | Log.d(TAG, "Parse exception thrown in onFinishSelect");
190 | }
191 | Log.d(TAG, "Time is: " + minDate.getTimeInMillis());
192 | value = String.valueOf(minDate.getTimeInMillis());
193 | new GetJSONTask().execute(type, value);
194 | // refreshMap();
195 | }
196 |
197 | private void refreshMap(ArrayList entries){
198 | googleMap.clear();
199 |
200 | // For showing a move to my location button
201 | googleMap.setMyLocationEnabled(true);
202 | ClusterManager clusterManager =
203 | new ClusterManager(getActivity().getApplicationContext(), googleMap);
204 | // For dropping a marker at a point on the Map
205 | double lat = (ForegroundService.FusedApiLatitude != null) ?
206 | ForegroundService.FusedApiLatitude : -34;
207 | double lon = (ForegroundService.FusedApiLongitude != null) ?
208 | ForegroundService.FusedApiLongitude : 151;
209 | LatLng curLoc = new LatLng(lat, lon);
210 | double latAvg = 0;
211 | double longAvg = 0;
212 |
213 | // Trying a few different approaches below. First, if there are no entries retrieved from
214 | // the server, we resort to using the locally stored data. This was implemented for
215 | // testing the map out, and I would recommend removing this feature to prevent any
216 | // confusion.
217 |
218 | // In the event that there are entries retrieved from the server, we display them. The most
219 | // basic approach to this is just to create standard markers and add some of the entry
220 | // information to them. Given the large amount of data presented, this is not realistic
221 | // for map responsiveness.
222 |
223 | // To fix the issue of displaying large amounts of data, we look to using clustering. There
224 | // are two approaches to this, custom and using the Google Maps Cluster Manager. So far, the
225 | // custom clustering approach is not complete, as it needs much better fine-grained tuning.
226 | // The Cluster Manager takes care of clustering the data points, but we need more control
227 | // over how these clusters are displayed. Currently each cluster shows how many markers are
228 | // contained within, but we want to display the average signal strength to the user.
229 |
230 |
231 | // TODO:
232 | // - Determine if the Cluster Manager can be used to show the data we want
233 | // - Split data between 3G and LTE (add toggle in UI)
234 | // - Filter out stale entries
235 | // - Adjust map zoom to contain all points/clusters (sometimes zooms in too much)
236 |
237 | if(entries == null){
238 | String rawQuery = "SELECT * FROM mapRecords";
239 | DBHandler dbHandler = new DBHandler(getActivity().getApplicationContext());
240 | SQLiteDatabase sqLiteDatabase = dbHandler.getWritableDatabase();
241 | Cursor cur = sqLiteDatabase.rawQuery(rawQuery, null);
242 |
243 |
244 | double count = DatabaseUtils.queryNumEntries(sqLiteDatabase, "mapRecords");
245 |
246 | if(cur.moveToFirst()){
247 | do{
248 | LatLng temp = new LatLng(cur.getDouble(1), cur.getDouble(2));
249 | latAvg += (cur.getDouble(1) / count);
250 | longAvg += (cur.getDouble(2) / count);
251 |
252 | // Log.d("LOCDB", "Lat is: " + cur.getDouble(1));
253 | // Log.d("LOCDB", "Long is: " + cur.getDouble(2));
254 | googleMap.addMarker(
255 | new MarkerOptions()
256 | .position(temp)
257 | .title(networkTypeMap[cur.getInt(5)])
258 | .snippet(cur.getInt(11) + " dBm")
259 | .icon(BitmapDescriptorFactory.
260 | defaultMarker(colorMap[cur.getInt(12)])));
261 |
262 |
263 | }
264 | while(cur.moveToNext());
265 | }
266 | else{
267 | googleMap.addMarker(new MarkerOptions().position(curLoc).title("Current Location").snippet("No data"));
268 | }
269 | cur.close();
270 | sqLiteDatabase.close();
271 | }
272 | else{
273 | // Custom cluster method - currently not working correctly
274 | // List clusters = init(entries, 200);
275 | // calculate(clusters, entries);
276 | //
277 | // for(Cluster cluster: clusters){
278 | // LatLng temp = new LatLng(cluster.centroid.getLatitude(), cluster.centroid.getLongitude());
279 | // latAvg += (cluster.centroid.getLatitude() / clusters.size());
280 | // longAvg += (cluster.centroid.getLongitude() / clusters.size());
281 | //
282 | // googleMap.addMarker(
283 | // new MarkerOptions()
284 | // .position(temp)
285 | // .title("Cluster " + cluster.id)
286 | // .snippet("Number of entries: " + cluster.getEntries().size())
287 | // );
288 | // }
289 |
290 |
291 | for(Entry e: entries){
292 | // LatLng temp = new LatLng(e.coordinate.getLatitude(), e.coordinate.getLongitude());
293 | latAvg += (e.coordinate.getLatitude() / entries.size());
294 | longAvg += (e.coordinate.getLongitude() / entries.size());
295 | // For Cluster Manager approach
296 | clusterManager.addItem(e);
297 |
298 | // Uncomment for basic marker approach
299 | // googleMap.addMarker(
300 | // new MarkerOptions()
301 | // .position(temp)
302 | // .title(networkTypeMap[e.networkCellType])
303 | // .snippet(e.dbm + " dBm")
304 | // .icon(BitmapDescriptorFactory.
305 | // defaultMarker(colorMap[e.signalLevel])));
306 | }
307 |
308 | // Only needed for Cluster Manager
309 | googleMap.setOnCameraIdleListener(clusterManager);
310 | googleMap.setOnMarkerClickListener(clusterManager);
311 | }
312 |
313 |
314 | if(latAvg != 0 && longAvg != 0) curLoc = new LatLng(latAvg, longAvg);
315 | // For zooming automatically to the location of the marker
316 | CameraPosition cameraPosition = new CameraPosition.Builder().target(curLoc).zoom(12).build();
317 | googleMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
318 | }
319 |
320 | private ArrayList init(List entries, int numClusters){
321 | Log.d(TAG, "Intitializing K-means");
322 | ArrayList clusters= new ArrayList();
323 | double minLat, minLong;
324 | minLat = minLong = Double.MAX_VALUE;
325 | double maxLat, maxLong;
326 | maxLat = maxLong = Double.MAX_VALUE * -1;
327 |
328 | for(Entry e: entries){
329 | minLat = Math.min(minLat, e.coordinate.getLatitude());
330 | minLong = Math.min(minLong, e.coordinate.getLongitude());
331 | maxLat = Math.max(maxLat, e.coordinate.getLatitude());
332 | maxLong = Math.max(maxLong, e.coordinate.getLongitude());
333 | // Log.d(TAG, "Max long: " + maxLong + " entry long: " + e.coordinate.getLongitude());
334 | }
335 |
336 | Log.d(TAG, "Min latitude: " + minLat + " max latitude: " + maxLat);
337 | Log.d(TAG, "Min longitude: " + minLong + " max longitude " + maxLong);
338 | for(int i = 0; i < numClusters; ++i){
339 | Cluster cluster = new Cluster(i);
340 | Coordinate centroid = Coordinate.createRandomCoordinate(maxLat, minLat, minLong, maxLong);
341 | cluster.setCentroid(centroid);
342 | clusters.add(cluster);
343 | }
344 |
345 | Log.d(TAG, "K-means initialization complete");
346 | return clusters;
347 | }
348 |
349 | private void calculate(List clusters, List entries){
350 | Log.d(TAG, "K-means calculation beginning...");
351 | boolean finish = false;
352 | int iteration = 0;
353 |
354 | while(!finish){
355 | clearClusters(clusters);
356 |
357 | List lastCentroids = getCentroids(clusters);
358 |
359 | assignCluster(entries, clusters);
360 |
361 | calculateCentroids(clusters);
362 |
363 | iteration++;
364 |
365 | List currentCentroids = getCentroids(clusters);
366 |
367 | double distance = 0;
368 | for(int i = 0; i < lastCentroids.size(); ++i){
369 | distance += Coordinate.distance(lastCentroids.get(i), currentCentroids.get(i));
370 | }
371 |
372 | if(distance == 0){
373 | finish = true;
374 | }
375 | if(iteration % 100 == 0){
376 | Log.d(TAG, "Iteration: " + iteration);
377 | }
378 | }
379 |
380 | Log.d(TAG, "K-means calculating complete.");
381 | }
382 |
383 | private void clearClusters(List clusters){
384 | for(Cluster cluster: clusters){
385 | cluster.clear();
386 | }
387 | }
388 |
389 | private List getCentroids(List clusters){
390 | List centroids = new ArrayList();
391 | for(Cluster cluster: clusters){
392 | Coordinate aux = cluster.getCentroid();
393 | Coordinate coordinate = new Coordinate(aux.getLatitude(),aux.getLongitude());
394 | centroids.add(coordinate);
395 | }
396 | return centroids;
397 | }
398 |
399 | private void assignCluster(List entries, List clusters){
400 | double max = Double.MAX_VALUE;
401 | double min = max;
402 | int cluster = 0;
403 | double distance = 0.0;
404 |
405 | for(Entry entry: entries){
406 | min = max;
407 | for(int i = 0; i < clusters.size(); ++i){
408 | Cluster c = clusters.get(i);
409 | distance = Coordinate.distance(entry.coordinate, c.getCentroid());
410 | if(distance < min){
411 | min = distance;
412 | cluster = i;
413 | }
414 | }
415 | entry.clusterNumber = cluster;
416 | clusters.get(cluster).addEntry(entry);
417 | }
418 | }
419 |
420 | private void calculateCentroids(List clusters){
421 | for(Cluster cluster: clusters){
422 | double sumLat = 0;
423 | double sumLong = 0;
424 | List entries = cluster.getEntries();
425 | int npoints = entries.size();
426 |
427 | for(Entry entry: entries){
428 | sumLat += entry.coordinate.getLatitude();
429 | sumLong += entry.coordinate.getLongitude();
430 | }
431 |
432 | Coordinate centroid = cluster.getCentroid();
433 | if(npoints > 0){
434 | double newLat = sumLat / npoints;
435 | double newLong = sumLong / npoints;
436 | centroid.setLatitude(newLat);
437 | centroid.setLongitude(newLong);
438 | }
439 | }
440 | }
441 |
442 | // Task that gets the earliest date for a user.
443 | // TODO:
444 | // - Get maximum date as well.
445 | // - Basic error handling
446 |
447 | class MinDateTask extends AsyncTask {
448 | private String type;
449 | @Override
450 | protected Long doInBackground(String... params) {
451 | type = params[0];
452 | if(mindate != null) return mindate;
453 | String IMEI_HASH = "";
454 | String responseStr = "";
455 | Long ret = System.currentTimeMillis();
456 | try {
457 | /*HASH IMEI*/
458 | IMEI_HASH = genHash(getIMEI());
459 | }
460 | catch (NoSuchAlgorithmException e) {
461 | e.printStackTrace();
462 | }
463 | HttpResponse response = null;
464 | try {
465 | HttpClient client = new DefaultHttpClient();
466 | HttpGet request = new HttpGet();
467 | String customURL = "http://104.196.177.7/aggregator/mindate?imei_hash="
468 | + URLEncoder.encode(IMEI_HASH, "UTF-8");
469 | // Log.d(TAG, customURL);
470 | request.setURI(new URI(customURL));
471 | response = client.execute(request);
472 |
473 | responseStr = EntityUtils.toString(response.getEntity());
474 | Log.v(TAG, "RESPONSE" + responseStr);
475 |
476 | /*PARSE JSON RESPONSE*/
477 | JSONObject jsonObject = new JSONObject(responseStr);
478 | String status = jsonObject.getString("status");
479 | if(status.equals("SUCCESS")){
480 | String time = jsonObject.getString("timestamp");
481 |
482 | SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
483 | sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
484 |
485 | long timestamp = Long.parseLong(time);
486 | String parsed = sdf.format(new Date(timestamp));
487 | Log.d(TAG, "Mindate: " + parsed);
488 | ret = timestamp;
489 | }
490 | } catch (URISyntaxException | IOException | JSONException e) {
491 | e.printStackTrace();
492 | }
493 | return ret;
494 | }
495 |
496 | @Override
497 | protected void onPostExecute(Long timestamp) {
498 | switch (type){
499 | case "day":
500 | Log.d(TAG, "Timestamp retrieved for day");
501 | DatePickerFragment fragment = DatePickerFragment.newInstance(timestamp); //new DatePickerFragment();
502 | fragment.setTargetFragment(MapFragment.this, 0);
503 | fragment.show(getActivity().getFragmentManager(), "datePicker");
504 | break;
505 | case "week":
506 | Log.d(TAG, "Timestamp retrieved for week");
507 | WeekPickerFragment weekPickerFragment = WeekPickerFragment.newInstance(timestamp);
508 | weekPickerFragment.setTargetFragment(MapFragment.this, 1);
509 | weekPickerFragment.show(getActivity().getFragmentManager(), "weekPicker");
510 | break;
511 | case "month":
512 | Log.d(TAG, "Timestamp retrieved for month");
513 | MonthPickerFragment monthPickerFragment = MonthPickerFragment.newInstance(timestamp);
514 | monthPickerFragment.setTargetFragment(MapFragment.this, 2);
515 | monthPickerFragment.show(getActivity().getFragmentManager(), "monthPicker");
516 | break;
517 | case "start":
518 | Log.d(TAG, "Timestamp cached.");
519 | mindate = timestamp;
520 | break;
521 | default:
522 | Log.d(TAG, "Other selected");
523 | // return super.onOptionsItemSelected(item);
524 | }
525 | }
526 | }
527 |
528 | class GetJSONTask extends AsyncTask{
529 | private ArrayList entryList;
530 | public GetJSONTask(){
531 | entryList = new ArrayList();
532 | }
533 |
534 | @Override
535 | protected Boolean doInBackground(String... strings) {
536 | String timespan = strings[0];
537 | String timestart = strings[1];
538 | Boolean ret = false;
539 |
540 | String IMEI_HASH = "";
541 | String responseStr = "";
542 | try {
543 | /*HASH IMEI*/
544 | IMEI_HASH = genHash(getIMEI());
545 | }
546 | catch (NoSuchAlgorithmException e) {
547 | e.printStackTrace();
548 | }
549 | HttpResponse response = null;
550 | try {
551 | HttpClient client = new DefaultHttpClient();
552 | HttpGet request = new HttpGet();
553 | // String customURL = "http://104.196.177.7/aggregator/genjson?imei_hash="
554 | // + URLEncoder.encode(IMEI_HASH, "UTF-8");
555 | String customURL = "http://104.196.177.7/aggregator/genjson?";
556 | List params = new LinkedList();
557 | params.add(new BasicNameValuePair("imei_hash", IMEI_HASH));
558 | params.add(new BasicNameValuePair("timespan", timespan));
559 | params.add(new BasicNameValuePair("timestart", timestart));
560 | String paramString = URLEncodedUtils.format(params, "utf-8");
561 |
562 | customURL += paramString;
563 |
564 | // Log.d(TAG, customURL);
565 | request.setURI(new URI(customURL));
566 | response = client.execute(request);
567 |
568 | responseStr = EntityUtils.toString(response.getEntity());
569 | Log.v(TAG, "JSON received.");
570 |
571 |
572 | /*PARSE JSON RESPONSE*/
573 | JSONObject jsonObject = new JSONObject(responseStr);
574 | String status = jsonObject.getString("status");
575 | if(status.equals("SUCCESS")){
576 | JSONObject data = jsonObject.getJSONObject("data");
577 | JSONArray entries = data.getJSONArray("entries");
578 | Log.d(TAG, entries.length() + " entries for selected timeframe");
579 | for(int i = 0; i < entries.length(); ++i){
580 | JSONObject jsonentry = entries.getJSONObject(i);
581 | // Log.d(TAG, entry.toString());
582 | Entry entry = Entry.mapJSON(jsonentry);
583 | entryList.add(entry);
584 | }
585 | ret = true;
586 | }
587 |
588 | } catch (URISyntaxException | IOException | JSONException e) {
589 | e.printStackTrace();
590 | }
591 | return ret;
592 | }
593 |
594 | @Override
595 | protected void onPostExecute(Boolean b){
596 | if(b){
597 | refreshMap(entryList);
598 | }
599 | else{
600 | Log.d(TAG, "No data for selected date");
601 | // Add popup alert
602 | }
603 | }
604 | }
605 |
606 | private String genHash(String input) throws NoSuchAlgorithmException
607 | {
608 | String IMEI_Base64="";
609 | try
610 | {
611 | MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
612 | byte[] sha256Hash = sha256.digest(input.getBytes("UTF-8"));
613 | IMEI_Base64 = Base64.encodeToString(sha256Hash, Base64.DEFAULT);
614 | IMEI_Base64=IMEI_Base64.replaceAll("\n", "");
615 | }
616 | catch(Exception e)
617 | {
618 | e.printStackTrace();
619 | }
620 | return IMEI_Base64;
621 | }
622 |
623 | private String getIMEI() {
624 | TelephonyManager telephonyManager =
625 | (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
626 | return telephonyManager.getDeviceId();
627 | }
628 | }
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/MonthPickerFragment.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.AlertDialog;
4 | import android.app.Dialog;
5 | import android.app.DialogFragment;
6 | import android.content.DialogInterface;
7 | import android.os.Bundle;
8 | import android.util.Log;
9 |
10 | import java.text.SimpleDateFormat;
11 | import java.util.ArrayList;
12 | import java.util.Calendar;
13 | import java.util.HashMap;
14 |
15 | import static android.R.attr.minDate;
16 |
17 | /**
18 | * Created by pcoonan on 4/6/17.
19 | */
20 |
21 | public class MonthPickerFragment extends DialogFragment {
22 |
23 | public final String TAG = "[CELNETMON-MONTHFRAG]";
24 | private static int selectedItem = 0;
25 | private static HashMap monthMap = new HashMap<>();
26 | public final String[] months = {"January", "February", "March",
27 | "April", "May", "June",
28 | "July", "August", "September",
29 | "October", "November", "December"};
30 |
31 | public static MonthPickerFragment newInstance(long mindate){
32 | MonthPickerFragment fragment = new MonthPickerFragment();
33 |
34 | Bundle args = new Bundle();
35 | args.putLong("mindate", mindate);
36 | fragment.setArguments(args);
37 |
38 | return fragment;
39 | }
40 |
41 | @Override
42 | public Dialog onCreateDialog(Bundle savedInstanceState){
43 | Long mindate = getArguments().getLong("mindate");
44 |
45 | AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
46 | alertDialogBuilder.setTitle("Select month");
47 |
48 | Calendar minDate = Calendar.getInstance();
49 | minDate.setTimeInMillis(mindate);
50 |
51 | // Add a month to have the first full month of data
52 | minDate.add(Calendar.MONTH, 1);
53 | minDate.set(Calendar.DAY_OF_MONTH, 1);
54 |
55 | Calendar maxDate = Calendar.getInstance();
56 | maxDate.add(Calendar.DATE, -2);
57 | maxDate.add(Calendar.MONTH, -1);
58 | ArrayList monthList = new ArrayList();
59 |
60 | int month = maxDate.get(Calendar.MONTH);
61 | int year = maxDate.get(Calendar.YEAR);
62 | int i = 0;
63 | // for(int i = 0; i < 24; ++i){
64 | while(maxDate.after(minDate)){
65 | monthList.add(months[month] + " " + year);
66 | monthMap.put(i, month + "/01/" + year);
67 | i++;
68 | maxDate.add(Calendar.MONTH, -1);
69 |
70 | month = maxDate.get(Calendar.MONTH);
71 | year = maxDate.get(Calendar.YEAR);
72 | }
73 |
74 | final CharSequence[] finalMonths = new CharSequence[monthList.size()];
75 | int index = 0;
76 | for(String mon : monthList){
77 | finalMonths[index++] = mon;
78 | }
79 | alertDialogBuilder.setSingleChoiceItems(finalMonths, selectedItem, new DialogInterface.OnClickListener() {
80 | @Override
81 | public void onClick(DialogInterface dialog, int which) {
82 | selectedItem = which;
83 | sendBackResult();
84 | }
85 | });
86 | return alertDialogBuilder.create();
87 | }
88 |
89 | public void sendBackResult(){
90 | DateSelectedListener listener = (DateSelectedListener) getTargetFragment();
91 | listener.onFinishSelect("month", monthMap.get(selectedItem));
92 | dismiss();
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/NetworkStateReceiver.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.ConnectivityManager;
7 | import android.net.NetworkInfo;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | /**
13 | * Created by AmmY on 01/09/16.
14 | */
15 | public class NetworkStateReceiver extends BroadcastReceiver
16 | {
17 |
18 | static List listeners;
19 | protected Boolean connected;
20 | public final String TAG = "[NW-STATE-RCVR]";
21 |
22 |
23 |
24 | public NetworkStateReceiver()
25 | {
26 | listeners = new ArrayList<>();
27 | connected = null;
28 | }
29 |
30 |
31 | public static int TYPE_WIFI = 1;
32 | public static int TYPE_MOBILE = 2;
33 | public static int TYPE_NOT_CONNECTED = 0;
34 |
35 |
36 | public static int getConnectivityStatus(Context context)
37 | {
38 | ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
39 |
40 | NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
41 | if (null != activeNetwork)
42 | {
43 | if(activeNetwork.getType() == ConnectivityManager.TYPE_WIFI)
44 | return TYPE_WIFI;
45 |
46 | if(activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE)
47 | return TYPE_MOBILE;
48 | }
49 | return TYPE_NOT_CONNECTED;
50 | }
51 |
52 | public static String getConnectivityStatusString(Context context)
53 | {
54 | int conn = getConnectivityStatus(context);
55 | String status = null;
56 | if (conn == TYPE_WIFI)
57 | {
58 | status = "Wifi enabled";
59 | }
60 | else if (conn == TYPE_MOBILE)
61 | {
62 | status = "Mobile data enabled";
63 | }
64 | else if (conn == TYPE_NOT_CONNECTED)
65 | {
66 | status = "Not connected to Internet";
67 | }
68 | return status;
69 | }
70 |
71 | @Override
72 | public void onReceive(Context context, Intent intent)
73 | {
74 | if (intent == null || intent.getExtras() == null)
75 | return;
76 |
77 | ConnectivityManager manager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
78 | NetworkInfo ni = manager.getActiveNetworkInfo();
79 |
80 | if (ni != null && ni.getState() == NetworkInfo.State.CONNECTED)
81 | {
82 | connected = true;
83 | }
84 | else if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE))
85 | {
86 | connected = false;
87 | }
88 |
89 | notifyStateToAll();
90 | }
91 |
92 | private void notifyStateToAll()
93 | {
94 | for (NetworkStateReceiverListener listener : listeners) {
95 | //Log.e("NSR","Listener ");
96 | notifyState(listener);
97 | }
98 | }
99 |
100 | private void notifyState(NetworkStateReceiverListener listener)
101 | {
102 | if (connected == null || listener == null)
103 | return;
104 |
105 | if (connected == true)
106 | listener.networkAvailable();
107 | else
108 | listener.networkUnavailable();
109 |
110 | }
111 |
112 | public void addListener(NetworkStateReceiverListener l)
113 | {
114 | listeners.add(l);
115 | notifyState(l);
116 | }
117 |
118 | public void removeListener(NetworkStateReceiverListener l)
119 | {
120 | listeners.remove(l);
121 | }
122 |
123 | public interface NetworkStateReceiverListener
124 | {
125 | void networkAvailable();
126 | void networkUnavailable();
127 | }
128 | }
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/PhoneCallState.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | /**
4 | * Created by Gautam on 7/3/16.
5 | * MBP111.0138.B16
6 | * agautam2@buffalo.edu
7 | * University at Buffalo, The State University of New York.
8 | * Copyright © 2016 Gautam. All rights reserved.
9 | */
10 |
11 | import java.util.Date;
12 |
13 | import android.content.BroadcastReceiver;
14 | import android.content.Context;
15 | import android.content.Intent;
16 | import android.telephony.TelephonyManager;
17 |
18 | public class PhoneCallState extends BroadcastReceiver
19 | {
20 | private static int lastState = TelephonyManager.CALL_STATE_IDLE;
21 | private static Date callStartTime;
22 | private static boolean isIncoming;
23 | private static String savedNumber; //because the passed incoming is only valid in ringing
24 |
25 |
26 | @Override
27 | public void onReceive(Context context, Intent intent)
28 | {
29 | //Log.d("onReceive", "onReceive: inside onReceive ");
30 | if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL"))
31 |
32 | {
33 | //Log.d("onReceive", "onReceive: inside onReceive of outgoing call ");
34 | savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
35 | }
36 | else
37 | {
38 | String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
39 | String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
40 | int state = 0;
41 | if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE))
42 | {
43 | state = TelephonyManager.CALL_STATE_IDLE;
44 | }
45 | else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
46 | {
47 | state = TelephonyManager.CALL_STATE_OFFHOOK;
48 | }
49 | else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING))
50 | {
51 | state = TelephonyManager.CALL_STATE_RINGING;
52 | }
53 |
54 | onCallStateChanged(context, state, number);
55 | }
56 |
57 | }
58 |
59 | //TODO Override
60 | protected void onIncomingCallStarted(Context ctx, String number, Date start){}
61 | protected void onOutgoingCallStarted(Context ctx, String number, Date start){}
62 | protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){}
63 | protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end){}
64 | protected void onMissedCall(Context ctx, String number, Date start){}
65 |
66 |
67 | //Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
68 | //Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
69 | public void onCallStateChanged(Context context, int state, String number)
70 | {
71 | //Log.v("TAG","state is "+ state);
72 | if(lastState == state)
73 | {
74 | return;
75 | }
76 | switch (state)
77 | {
78 | case TelephonyManager.CALL_STATE_RINGING:
79 | isIncoming = true;
80 | callStartTime = new Date();
81 | savedNumber = number;
82 | //Log.v("TAG","Ringing");
83 | break;
84 | case TelephonyManager.CALL_STATE_OFFHOOK:
85 | //Log.v("TAG","Offhook");
86 | //Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
87 | if(lastState != TelephonyManager.CALL_STATE_RINGING)
88 | {
89 | isIncoming = false;
90 | callStartTime = new Date();
91 | //Log.v("TAG","Call started outgoing");
92 | onOutgoingCallStarted(context, savedNumber, callStartTime);
93 | }
94 | if(lastState == TelephonyManager.CALL_STATE_RINGING)
95 | {
96 | //Log.v("TAG","Picked up");
97 | onIncomingCallStarted(context, number, callStartTime);
98 | }
99 | break;
100 | case TelephonyManager.CALL_STATE_IDLE:
101 | //Went to idle- this is the end of a call. What type depends on previous state(s)
102 | if(lastState == TelephonyManager.CALL_STATE_RINGING)
103 | {
104 | //Ring but no pickup- a miss
105 | //Log.v("TAG","Missed");
106 | onMissedCall(context, savedNumber, callStartTime);
107 | }
108 | else if(isIncoming)
109 | {
110 | onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
111 | }
112 | else
113 | {
114 | onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
115 | }
116 | break;
117 | }
118 | lastState = state;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/PhoneCallStateRecorder.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.content.Context;
4 |
5 | import java.util.Date;
6 |
7 | /**
8 | * Created by Gautam on 7/3/16.
9 | * MBP111.0138.B16
10 | * agautam2@buffalo.edu
11 | * University at Buffalo, The State University of New York.
12 | * Copyright © 2016 Gautam. All rights reserved.
13 | */
14 | public class PhoneCallStateRecorder extends PhoneCallState
15 | {
16 | public static int call_state = 0;
17 | static final String TAG = "[CELNETMON-PCSR]";
18 | @Override
19 | protected void onIncomingCallStarted(Context ctx, String number, Date start)
20 | {
21 | //Log.v(TAG, "Call Received from: " + number + " at: " + start);
22 | call_state = 1;
23 | }
24 |
25 | @Override
26 | protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
27 | {
28 | //Log.v(TAG, "Call Received from: " + number + " at: " + start + " ended at: " + end);
29 | call_state = 0;
30 | }
31 |
32 | @Override
33 | protected void onOutgoingCallStarted(Context ctx, String number, Date start)
34 | {
35 | //Log.v(TAG, "Outgoing call to: " + number + " started at: " + start);
36 | call_state = 1;
37 | }
38 |
39 | @Override
40 | protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end)
41 | {
42 | //Log.v(TAG, "Outgoing call to: " + number + " started at: " + start + " ended at: " + end);
43 | call_state = 0;
44 | }
45 |
46 | @Override
47 | protected void onMissedCall(Context ctx, String number, Date start)
48 | {
49 | //Log.v(TAG, "Missed call from: " + number + " at: " + start);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/ScheduleIntentReceiver.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.Service;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.location.Location;
7 | import android.location.LocationManager;
8 | import android.os.IBinder;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.telephony.TelephonyManager;
11 | import android.util.Base64;
12 | import android.util.Log;
13 | import android.widget.Toast;
14 |
15 | import org.apache.http.HttpResponse;
16 | import org.apache.http.client.ClientProtocolException;
17 | import org.apache.http.client.HttpClient;
18 | import org.apache.http.client.methods.HttpGet;
19 | import org.apache.http.impl.client.DefaultHttpClient;
20 |
21 | import java.io.IOException;
22 | import java.net.URI;
23 | import java.net.URISyntaxException;
24 | import java.net.URLEncoder;
25 | import java.security.MessageDigest;
26 | import java.security.NoSuchAlgorithmException;
27 | import java.security.Provider;
28 |
29 |
30 | /**
31 | * Created by Gautam on 7/18/16.
32 | * MBP111.0138.B16
33 | * agautam2@buffalo.edu
34 | * University at Buffalo, The State University of New York.
35 | * Copyright © 2016 Gautam. All rights reserved.
36 | */
37 | public class ScheduleIntentReceiver extends Service {
38 | // LocationFinder locationFinder;
39 | CellularDataRecorder cdr;
40 | PhoneCallStateRecorder pcsr;
41 | DBstore dbStore;
42 | public final String TAG = "[CELNETMON-HNDLRCVR]";
43 | int keepAlive = 0;
44 | String IMEI_HASH;
45 | String IMEI;
46 |
47 | public void onScheduleIntentReceiver(Context arg0) {
48 | keepAlive++;
49 |
50 | // locationFinder = new LocationFinder(arg0);
51 |
52 | final TelephonyManager telephonyManager =
53 | (TelephonyManager) arg0.getSystemService(Context.TELEPHONY_SERVICE);
54 | IMEI = telephonyManager.getDeviceId();
55 | cdr = new CellularDataRecorder();
56 | pcsr = new PhoneCallStateRecorder();
57 |
58 | // locationFinder = new LocationFinder(arg0);
59 | //Log.v(TAG, "Calling getLocalTimeStamp and getCellularInfo");
60 |
61 | /*FETCH INFO FROM CDR CLASS*/
62 | Long timeStamp = cdr.getLocalTimeStamp();
63 | String cellularInfo = cdr.getCellularInfo(telephonyManager);
64 | int dataActivity = cdr.getCurrentDataActivity(telephonyManager);
65 | int dataState = cdr.getCurrentDataState(telephonyManager);
66 | int mobileNetworkType = cdr.getMobileNetworkType(telephonyManager);
67 |
68 | final LocationManager locationManager = (LocationManager) arg0.getSystemService(LOCATION_SERVICE);
69 |
70 | if (ForegroundService.FusedApiLatitude == null || ForegroundService.FusedApiLongitude == null) {
71 | return;
72 | }
73 |
74 | /*FETCH INFO FROM FUSED API*/
75 | Double fusedApiLatitude = ForegroundService.FusedApiLatitude;
76 | Double fusedApiLongitude = ForegroundService.FusedApiLongitude;
77 | boolean stale = ((System.currentTimeMillis() - ForegroundService.LastFusedLocation) > 40000)
78 | && dataState == 0 && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
79 |
80 | Double locationdata[] = {fusedApiLatitude, fusedApiLongitude};
81 |
82 |
83 | /*FETCH INFO FROM PCSR CLASS*/
84 | int phoneCallState = PhoneCallStateRecorder.call_state;
85 | // Log.i(TAG, "onReceive: Location data is before inserting "+locationdata[0] +" "+ locationdata[1]);
86 | //
87 | //
88 | // Log.v(TAG, "TIME STAMP: " + timeStamp);
89 | // Log.v(TAG, "CELLULAR INFO: " + cellularInfo);
90 | // Log.v(TAG, "DATA ACTIVITY: " + dataActivity);
91 | // Log.v(TAG, "DATA STATE: " + dataState);
92 | // Log.v(TAG, "MOBILE NETWORK TYPE: " + mobileNetworkType);
93 |
94 | dbStore = new DBstore(arg0);
95 | dbStore.insertIntoDB(locationdata, stale, timeStamp, cellularInfo, dataActivity, dataState,
96 | phoneCallState, mobileNetworkType);
97 | // Log.e(TAG, "KEEPALIVE: " + keepAlive);
98 | // Ping every hour -> 3600 / log frequency
99 | if (keepAlive == 360) {
100 | /*GET IMEI*/
101 | try {
102 | /*HASH IMEI*/
103 | IMEI_HASH = genHash(IMEI);
104 | } catch (NoSuchAlgorithmException e) {
105 | e.printStackTrace();
106 | }
107 | Log.v(TAG, "GENERATED IMEI HASH");
108 | //TODO KEEP-ALIVE GET
109 | HttpResponse response = null;
110 | try {
111 | HttpClient client = new DefaultHttpClient();
112 | HttpGet request = new HttpGet();
113 | String customURL = "http://104.196.177.7/aggregator/ping?imei_hash="
114 | + URLEncoder.encode(IMEI_HASH, "UTF-8");
115 | request.setURI(new URI(customURL));
116 | response = client.execute(request);
117 | Log.v(TAG, "RESPONSE PHRASE FOR HTTP GET: "
118 | + response.getStatusLine().getReasonPhrase());
119 | Log.v(TAG, "RESPONSE STATUS FOR HTTP GET: "
120 | + response.getStatusLine().getStatusCode());
121 | } catch (URISyntaxException e) {
122 | e.printStackTrace();
123 | } catch (ClientProtocolException e) {
124 | e.printStackTrace();
125 | } catch (IOException e) {
126 | e.printStackTrace();
127 | }
128 | //RESET KEEPALIVE
129 | keepAlive = 0;
130 | //Log.e(TAG, "KEEPALIVE RESET: " + keepAlive);
131 | }
132 |
133 | }
134 |
135 |
136 | private String genHash(String input) throws NoSuchAlgorithmException {
137 | String IMEI_Base64 = "";
138 | try {
139 | MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
140 | byte[] sha256Hash = sha256.digest(input.getBytes("UTF-8"));
141 | IMEI_Base64 = Base64.encodeToString(sha256Hash, Base64.DEFAULT);
142 | IMEI_Base64 = IMEI_Base64.replaceAll("\n", "");
143 | } catch (Exception e) {
144 | e.printStackTrace();
145 | }
146 | return IMEI_Base64;
147 | }
148 |
149 | @Override
150 | public IBinder onBind(Intent intent) {
151 | // Used only in case of bound services.
152 | return null;
153 | }
154 |
155 | }
156 |
157 |
158 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/Scheduler.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by Gautam on 7/26/16.
3 | * MBP111.0138.B16
4 | * agautam2@buffalo.edu
5 | * University at Buffalo, The State University of New York.
6 | * Copyright © 2016 Gautam. All rights reserved.
7 | */
8 |
9 | package edu.buffalo.cse.ubwins.cellmon;
10 |
11 | import android.content.Context;
12 | import android.util.Log;
13 | import java.util.concurrent.Executors;
14 | import java.util.concurrent.ScheduledExecutorService;
15 | import java.util.concurrent.ScheduledFuture;
16 | import static java.util.concurrent.TimeUnit.*;
17 |
18 |
19 | public class Scheduler
20 | {
21 | ScheduleIntentReceiver scheduleIntentReceiver = new ScheduleIntentReceiver();
22 | private static final String TAG = "[CELMON-SCHEDULER]";
23 | final static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
24 | public static ScheduledFuture> beeperHandle=null;
25 |
26 | public void beep(final Context context)
27 | {
28 | final Runnable beeper = new Runnable()
29 | {
30 | public void run()
31 | {
32 | //Log.v(LOG, "BEEP");
33 | try {
34 | scheduleIntentReceiver.onScheduleIntentReceiver(context);
35 | }
36 | catch (Exception e)
37 | {
38 | Log.e(TAG,"error in executing: It will no longer be run!: " + e.getMessage());
39 | e.printStackTrace();
40 | }
41 | }
42 | };
43 | beeperHandle = scheduler.scheduleAtFixedRate(beeper, 0, 10, SECONDS);
44 | }
45 |
46 | public static void stopScheduler()
47 | {
48 | scheduler.schedule(new Runnable()
49 | {
50 | public void run()
51 | {
52 | beeperHandle.cancel(true);
53 | }
54 | }, 1, SECONDS);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/StartMyServiceAtBootReceiver.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.preference.PreferenceManager;
8 | import android.util.Log;
9 | import android.widget.Toast;
10 |
11 | /**
12 | * Created by AmmY on 12/10/16.
13 | */
14 |
15 | public class StartMyServiceAtBootReceiver extends BroadcastReceiver {
16 | SharedPreferences preferences;
17 | @Override
18 | public void onReceive(Context context, Intent intent) {
19 | preferences = PreferenceManager.getDefaultSharedPreferences(context);
20 | if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
21 | if(preferences.getBoolean("TRACKING",false)) {
22 | Intent serviceIntent = new Intent(context, ForegroundService.class);
23 | serviceIntent.setAction("startforeground");
24 | context.startService(serviceIntent);
25 | }
26 | else{
27 | Log.v("Restart","Tracking was off");
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/edu/buffalo/cse/ubwins/cellmon/WeekPickerFragment.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import android.app.AlertDialog;
4 | import android.app.DatePickerDialog;
5 | import android.app.Dialog;
6 | import android.app.DialogFragment;
7 | import android.content.DialogInterface;
8 | import android.os.Bundle;
9 | import android.support.annotation.Nullable;
10 | import android.util.Log;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 | import android.view.WindowManager;
15 | import android.widget.EditText;
16 |
17 | import java.text.SimpleDateFormat;
18 | import java.util.ArrayList;
19 | import java.util.Calendar;
20 | import java.util.HashMap;
21 |
22 |
23 |
24 | /**
25 | * Created by pcoonan on 4/3/17.
26 | */
27 |
28 | public class WeekPickerFragment extends DialogFragment {
29 | // private EditText mEditText;
30 | private static int selectedItem = 0;
31 | private static HashMap weekMap = new HashMap<>();
32 | public final String TAG = "[CELNETMON-WEEKFRAG]";
33 |
34 | public static WeekPickerFragment newInstance(long mindate){
35 | WeekPickerFragment fragment = new WeekPickerFragment();
36 |
37 | Bundle args = new Bundle();
38 | args.putLong("mindate", mindate);
39 | fragment.setArguments(args);
40 |
41 | return fragment;
42 | }
43 |
44 |
45 | @Override
46 | public Dialog onCreateDialog(Bundle savedInstanceState){
47 | Long mindate = getArguments().getLong("mindate");
48 |
49 | AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());
50 | alertDialogBuilder.setTitle("Select week");
51 |
52 | Calendar maxDate = Calendar.getInstance();
53 | maxDate.add(Calendar.DATE, -7);
54 |
55 | Calendar minDate = Calendar.getInstance();
56 | minDate.setTimeInMillis(mindate);
57 |
58 | // Get start of week where data was first recorded
59 | minDate.add(Calendar.DAY_OF_WEEK, minDate.getFirstDayOfWeek() - minDate.get(Calendar.DAY_OF_WEEK));
60 | // Add a week to have the first full week of data
61 | minDate.add(Calendar.DAY_OF_YEAR, 7);
62 |
63 |
64 | SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
65 |
66 | Calendar beginWeek = (Calendar) maxDate.clone();
67 | ArrayList weeks = new ArrayList();
68 | beginWeek.add(Calendar.DAY_OF_WEEK, beginWeek.getFirstDayOfWeek() - beginWeek.get(Calendar.DAY_OF_WEEK));
69 | Calendar endWeek = (Calendar) beginWeek.clone();
70 | endWeek.add(Calendar.DAY_OF_WEEK, 6);
71 |
72 | int day = beginWeek.get(Calendar.DAY_OF_MONTH);
73 | int month = beginWeek.get(Calendar.MONTH);
74 | int year = beginWeek.get(Calendar.YEAR);
75 | // for(int i = 0; i < 104; ++i){
76 | int i = 0;
77 | while(beginWeek.after(minDate)){
78 | weeks.add(df.format(beginWeek.getTime()) + "-" + df.format(endWeek.getTime()));
79 | weekMap.put(i, month + "/" + day + "/" + year);
80 | i++;
81 | beginWeek.add(Calendar.DAY_OF_YEAR, -7);
82 | endWeek.add(Calendar.DAY_OF_YEAR, -7);
83 |
84 | day = beginWeek.get(Calendar.DAY_OF_MONTH);
85 | month = beginWeek.get(Calendar.MONTH);
86 | year = beginWeek.get(Calendar.YEAR);
87 | }
88 |
89 | final CharSequence[] finalWeeks = new CharSequence[weeks.size()];
90 | int index = 0;
91 | for(String week : weeks){
92 | finalWeeks[index++] = week;
93 | }
94 | alertDialogBuilder.setSingleChoiceItems(finalWeeks, selectedItem, new DialogInterface.OnClickListener() {
95 | @Override
96 | public void onClick(DialogInterface dialog, int which) {
97 | selectedItem = which;
98 | sendBackResult();
99 | }
100 | });
101 | return alertDialogBuilder.create();
102 | }
103 |
104 | public void sendBackResult(){
105 | DateSelectedListener listener = (DateSelectedListener) getTargetFragment();
106 | listener.onFinishSelect("week", weekMap.get(selectedItem));
107 | dismiss();
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/app/src/main/proto/data_record.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_package = "edu.buffalo.cse.ubwins.cellmon";
4 |
5 | message DataEntry {
6 | /* Timestamp */
7 | uint64 TIMESTAMP = 1;
8 |
9 | /* Location */
10 | double FUSED_LAT = 2;
11 | double FUSED_LONG = 3;
12 | bool STALE = 4;
13 |
14 | /* https://developer.android.com/reference/android/telephony/TelephonyManager.html */
15 | enum NetType {
16 | NETWORK_TYPE_UNKNOWN = 0;
17 | NETWORK_TYPE_GPRS = 1;
18 | NETWORK_TYPE_EDGE = 2;
19 | NETWORK_TYPE_UMTS = 3;
20 | NETWORK_TYPE_HSDPA = 4;
21 | NETWORK_TYPE_HSUPA = 5;
22 | NETWORK_TYPE_HSPA = 6;
23 | NETWORK_TYPE_CDMA = 7;
24 | NETWORK_TYPE_EVDO_0 = 8;
25 | NETWORK_TYPE_EVDO_A = 9;
26 | NETWORK_TYPE_EVDO_B = 10;
27 | NETWORK_TYPE_1xRTT = 11;
28 | NETWORK_TYPE_IDEN = 12;
29 | NETWORK_TYPE_LTE = 13;
30 | NETWORK_TYPE_EHRPD = 14;
31 | NETWORK_TYPE_HSPAP = 15;
32 | NETWORK_TYPE_GSM = 16;
33 | NETWORK_TYPE_TD_SCDMA = 17;
34 | NETWORK_TYPE_IWLAN = 18;
35 | }
36 | NetType NETWORK_TYPE = 5;
37 |
38 | /* https://developer.android.com/reference/android/telephony/TelephonyManager.html#getAllCellInfo() */
39 | enum CellType {
40 | GSM = 0;
41 | CDMA = 1;
42 | WCDMA = 2;
43 | LTE = 3;
44 | }
45 | CellType NETWORK_CELL_TYPE = 6;
46 |
47 | /* Network Parameters: https://developer.android.com/reference/android/telephony/TelephonyManager.html#getAllCellInfo() */
48 | int32 NETWORK_PARAM_1 = 7;
49 | int32 NETWORK_PARAM_2 = 8;
50 | int32 NETWORK_PARAM_3 = 9;
51 | int32 NETWORK_PARAM_4 = 10;
52 |
53 | /* https://developer.android.com/reference/android/telephony/CellSignalStrength.html */
54 | int32 SIGNAL_ASU_LEVEL = 11;
55 | sint32 SIGNAL_DBM = 12;
56 | int32 SIGNAL_LEVEL = 13;
57 |
58 | /* https://developer.android.com/reference/android/net/NetworkInfo.DetailedState.html */
59 | enum NetState {
60 | UNKNOWN = 0;
61 | IDLE = 1;
62 | SCANNING = 2;
63 | CONNECTING = 3;
64 | AUTHENTICATING = 4;
65 | OBTAINING_IPADDR = 5;
66 | CONNECTED = 6;
67 | SUSPENDED = 7;
68 | DISCONNECTING = 8;
69 | DISCONNECTED = 9;
70 | FAILED = 10;
71 | }
72 | NetState NETWORK_STATE = 14;
73 |
74 | /* https://developer.android.com/reference/android/telephony/TelephonyManager.html#getDataActivity() */
75 | enum DataActivity {
76 | DATA_ACTIVITY_NONE = 0;
77 | DATA_ACTIVITY_IN = 1;
78 | DATA_ACTIVITY_OUT = 2;
79 | DATA_ACTIVITY_INOUT = 3;
80 | DATA_ACTIVITY_DORMANT = 4;
81 | DATA_ACTIVITY_UNKNOWN = 5;
82 | }
83 | DataActivity NETWORK_DATA_ACTIVITY = 15;
84 |
85 | /* https://developer.android.com/reference/android/telephony/TelephonyManager.html */
86 | enum VoiceCallActivity {
87 | CALL_STATE_IDLE = 0;
88 | CALL_STATE_RINGING = 1;
89 | CALL_STATE_OFFHOOK = 2;
90 | }
91 | VoiceCallActivity VOICE_CALL_STATE = 16;
92 | }
93 |
94 | message DataRecord {
95 | string IMEI_HASH = 1;
96 | string NETWORK_OPERATOR_CODE = 2;
97 | string NETWORK_OPERATOR_NAME = 3;
98 |
99 | repeated DataEntry ENTRY = 4;
100 | }
101 |
--------------------------------------------------------------------------------
/app/src/main/proto/register_device.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option java_package = "edu.buffalo.cse.ubwins.cellmon";
4 |
5 | message RegisterDevice {
6 | string IMEI_HASH = 1;
7 |
8 | /* https://developer.android.com/reference/android/os/Build.html */
9 | string BOARD = 2;
10 | string BRAND = 3;
11 | string DEVICE = 4;
12 | string HARDWARE = 5;
13 | string MANUFACTURER = 6;
14 | string MODEL = 7;
15 | string PRODUCT = 8;
16 |
17 | /* https://developer.android.com/reference/android/telephony/TelephonyManager.html */
18 | string NETWORK_COUNTRY_ISO = 9;
19 | string NETWORK_OPERATOR_CODE = 10;
20 | string NETWORK_OPERATOR_NAME = 11;
21 | string PHONE_TYPE = 12;
22 | string SIM_COUNTRY_ISO = 13;
23 | string SIM_OPERATOR = 14;
24 | string SIM_OPERATOR_NAME = 15;
25 |
26 | /* https://developer.android.com/reference/android/os/Build.VERSION.html */
27 | string RELEASE = 16;
28 | string SDK_INT = 17;
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/move_left_in_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/move_left_out_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/move_right_in_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/move_right_out_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-hdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_date_range_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-hdpi/ic_date_range_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_date_range_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-hdpi/ic_date_range_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-hdpi/ic_drawer.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-mdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_date_range_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-mdpi/ic_date_range_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_date_range_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-mdpi/ic_date_range_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-mdpi/ic_drawer.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_date_range_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xhdpi/ic_date_range_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_date_range_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xhdpi/ic_date_range_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_drawer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xhdpi/ic_drawer.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_date_range_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xxhdpi/ic_date_range_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_date_range_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xxhdpi/ic_date_range_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_date_range_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xxxhdpi/ic_date_range_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_date_range_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/drawable-xxxhdpi/ic_date_range_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
4 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
16 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
29 |
30 |
39 |
40 |
50 |
51 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_pick_week.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/location_fragment.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
16 |
22 |
23 |
29 |
30 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/simple_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/app_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/home_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/map_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-hdpi/m.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/cse50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/cse50.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_action_about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/ic_action_about.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_action_computer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/ic_action_computer.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_action_place.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/ic_action_place.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_action_time.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/ic_action_time.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_globe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/ic_globe.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-mdpi/m.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-xhdpi/m.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-xxhdpi/m.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/m.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/app/src/main/res/mipmap-xxxhdpi/m.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 16dp
6 | 160dp
7 | 16dp
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | CellularNetworkMonitor
3 |
4 | Open navigation drawer
5 | Close navigation drawer
6 |
7 | OK
8 | Settings
9 | Map
10 | Home
11 | About Us
12 |
13 | Location Permission has been granted.
14 | Storage Permissions have been granted.
15 | WakeLock Permissions have been granted.
16 | Phone State Permissions have been granted.
17 | Permissions were not granted.
18 | Location permission is needed for the application to function correctly.
19 | Storage permissions are needed to be able to log the data to local memory.
20 | Phone state permissions are needed to be able to log the necessary data.
21 | Wake lock permissions are needed to be able to log the necessary data.
22 |
23 | - @string/app_menu_home
24 | - @string/app_menu_mapView
25 |
26 |
27 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/test/java/edu/buffalo/cse/ubwins/cellmon/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package edu.buffalo.cse.ubwins.cellmon;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.3.0'
9 | classpath 'com.google.gms:google-services:3.0.0'
10 |
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | jcenter()
20 | }
21 | }
22 |
23 | task clean(type: Delete) {
24 | delete rootProject.buildDir
25 | }
26 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | Default value: -Xmx2048M -XX:MaxPermSize=512m
13 | org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/gautamgitspace/CellularNetworkMonitor/cb9a45d2453c65c1959624975218062a42a1312f/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri May 12 15:39:10 EDT 2017
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------