├── .gitignore
├── HIPRIKeeper
├── .gitignore
├── .idea
│ ├── .name
│ ├── codeStyleSettings.xml
│ ├── compiler.xml
│ ├── copyright
│ │ ├── GPLv3.xml
│ │ └── profiles_settings.xml
│ ├── dictionaries
│ │ └── mbaerts.xml
│ ├── encodings.xml
│ ├── gradle.xml
│ ├── misc.xml
│ ├── modules.xml
│ ├── scopes
│ │ └── scope_settings.xml
│ └── vcs.xml
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── be
│ │ │ └── uclouvain
│ │ │ └── hiprikeeper
│ │ │ └── ApplicationTest.java
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── ic_launcher-web.png
│ │ ├── java
│ │ └── be
│ │ │ └── uclouvain
│ │ │ └── hiprikeeper
│ │ │ ├── Boot.java
│ │ │ ├── Config.java
│ │ │ ├── HIPRIKeeper.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MainService.java
│ │ │ ├── Manager.java
│ │ │ ├── MobileDataMgr.java
│ │ │ └── Notifications.java
│ │ └── res
│ │ ├── drawable-hdpi-v11
│ │ └── ic_stat_name.png
│ │ ├── drawable-hdpi-v9
│ │ └── ic_stat_name.png
│ │ ├── drawable-hdpi
│ │ └── ic_stat_name.png
│ │ ├── drawable-mdpi-v11
│ │ └── ic_stat_name.png
│ │ ├── drawable-mdpi-v9
│ │ └── ic_stat_name.png
│ │ ├── drawable-mdpi
│ │ └── ic_stat_name.png
│ │ ├── drawable-xhdpi-v11
│ │ └── ic_stat_name.png
│ │ ├── drawable-xhdpi-v9
│ │ └── ic_stat_name.png
│ │ ├── drawable-xhdpi
│ │ └── ic_stat_name.png
│ │ ├── drawable-xxhdpi-v11
│ │ └── ic_stat_name.png
│ │ ├── drawable-xxhdpi-v9
│ │ └── ic_stat_name.png
│ │ ├── drawable-xxhdpi
│ │ └── ic_stat_name.png
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ └── values
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── MultipathControl
├── .gitignore
├── .settings
│ └── org.eclipse.jdt.core.prefs
├── AUTHORS
├── AndroidManifest.xml
├── LICENSE
├── ic_launcher-web.png
├── libs
│ └── android-support-v4.jar
├── proguard-project.txt
├── res
│ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ │ └── ic_launcher.png
│ ├── layout
│ │ ├── main.xml
│ │ ├── tcp_cc.xml
│ │ └── tcp_cc_list_view.xml
│ ├── menu
│ │ └── main.xml
│ ├── values-sw600dp
│ │ └── dimens.xml
│ ├── values-sw720dp-land
│ │ └── dimens.xml
│ ├── values-v11
│ │ └── styles.xml
│ ├── values-v14
│ │ └── styles.xml
│ ├── values-w820dp
│ │ └── dimens.xml
│ └── values
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── styles.xml
└── src
│ └── be
│ └── uclouvain
│ └── multipathcontrol
│ ├── MPCtrl.java
│ ├── activities
│ ├── MainActivity.java
│ └── TCPCCActivity.java
│ ├── global
│ ├── Config.java
│ ├── ConfigServerExample.java
│ └── Manager.java
│ ├── ifaces
│ ├── IPRoute.java
│ └── MobileDataMgr.java
│ ├── services
│ ├── Boot.java
│ └── MainService.java
│ ├── stats
│ ├── GetIPTask.java
│ ├── HttpUtils.java
│ ├── JSONSender.java
│ ├── JSONSenderTask.java
│ ├── LocationState.java
│ ├── PhoneState.java
│ ├── SaveDataAbstract.java
│ ├── SaveDataApp.java
│ ├── SaveDataHandover.java
│ └── StatsCategories.java
│ ├── system
│ ├── Cmd.java
│ ├── IPRouteUtils.java
│ └── Sysctl.java
│ └── ui
│ └── Notifications.java
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | # built application files
2 | *.apk
3 | *.ap_
4 | .metadata
5 | .gradle
6 | build
7 |
8 | # files for the dex VM
9 | *.dex
10 |
11 | # Java class files
12 | *.class
13 |
14 | # generated files
15 | bin/
16 | gen/
17 |
18 | # Local configuration file (sdk path, etc)
19 | local.properties
20 |
21 | # Eclipse project files
22 | .classpath
23 | .project
24 | project.properties
25 |
26 | # Proguard folder generated by Eclipse
27 | proguard/
28 |
29 | # Intellij project files
30 | *.iml
31 | *.ipr
32 | *.iws/
33 | .idea/workspace.xml
34 | .idea/libraries
35 | google-play-services_lib
36 | .idea/dictionaries/*.xml
37 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /local.properties
3 | /.idea/workspace.xml
4 | /.idea/libraries
5 | .DS_Store
6 | /build
7 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/.name:
--------------------------------------------------------------------------------
1 | HIPRI Keeper
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/codeStyleSettings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
171 |
172 |
173 |
174 |
175 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.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 |
23 |
24 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/copyright/GPLv3.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/dictionaries/mbaerts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/scopes/scope_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/HIPRIKeeper/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | applicationId "be.uclouvain.hiprikeeper"
9 | minSdkVersion 16
10 | targetSdkVersion 19
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | compile 'com.android.support:appcompat-v7:22.0.0'
25 | }
26 |
--------------------------------------------------------------------------------
/HIPRIKeeper/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 android-sdk-linux/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 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/androidTest/java/be/uclouvain/hiprikeeper/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package be.uclouvain.hiprikeeper;
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 | }
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/Boot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.content.BroadcastReceiver;
23 | import android.content.Context;
24 | import android.content.Intent;
25 |
26 | public class Boot extends BroadcastReceiver {
27 | @Override
28 | public void onReceive(Context context, Intent intent) {
29 | if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
30 | context.startService(new Intent(context, MainService.class));
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/Config.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.content.Context;
23 | import android.content.SharedPreferences;
24 |
25 | /**
26 | * Created by Matthieu Baerts on 19/04/15.
27 | */
28 | public class Config {
29 | public static final String PREFS_NAME = "HIPRIKeeper";
30 | public static final String PREFS_STATUS = "enableMultiInterfaces";
31 | public static final String PREFS_SAVE_BATTERY = "saveBattery";
32 |
33 | public static boolean enable = true;
34 | public static boolean saveBattery = true;
35 |
36 | private Config() {
37 | }
38 |
39 | public static void getDefaultConfig(Context context) {
40 | SharedPreferences settings = context.getSharedPreferences(PREFS_NAME,
41 | Context.MODE_PRIVATE);
42 | enable = settings.getBoolean(PREFS_STATUS, true);
43 | saveBattery = settings.getBoolean(PREFS_SAVE_BATTERY, true);
44 | }
45 |
46 | public static void saveStatus(Context context) {
47 | SharedPreferences settings = context.getSharedPreferences(PREFS_NAME,
48 | Context.MODE_PRIVATE);
49 | SharedPreferences.Editor editor = settings.edit();
50 |
51 | editor.putBoolean(PREFS_STATUS, enable);
52 | editor.putBoolean(PREFS_SAVE_BATTERY, saveBattery);
53 | editor.apply();
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/HIPRIKeeper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.content.BroadcastReceiver;
23 | import android.content.Context;
24 | import android.content.Intent;
25 | import android.content.IntentFilter;
26 | import android.net.ConnectivityManager;
27 | import android.os.Handler;
28 | import android.os.PowerManager;
29 | import android.os.StrictMode;
30 | import android.util.Log;
31 |
32 | /**
33 | * Created by Matthieu Baerts on 19/04/15.
34 | */
35 | public class HIPRIKeeper {
36 |
37 | private Context context;
38 | private final Notifications notif;
39 | private final MobileDataMgr mobileDataMgr;
40 | private final Handler handler;
41 | private static long lastTimeHandler;
42 |
43 | public HIPRIKeeper(Context context) {
44 | this.context = context;
45 |
46 | StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
47 | StrictMode.setThreadPolicy(policy);
48 |
49 | Config.getDefaultConfig(context);
50 | notif = new Notifications(context);
51 | mobileDataMgr = new MobileDataMgr(context);
52 | Log.i(Manager.TAG, "new HIPRI Keeper");
53 |
54 | handler = new Handler();
55 | initHandler();
56 |
57 | /*
58 | * mConnReceiver will be called each time a change of connectivity
59 | * happen
60 | */
61 | context.registerReceiver(mConnReceiver, new IntentFilter(
62 | ConnectivityManager.CONNECTIVITY_ACTION));
63 |
64 | if (Config.enable)
65 | notif.showNotification();
66 | if (! Config.saveBattery)
67 | mobileDataMgr.keepMobileConnectionAlive();
68 | }
69 |
70 | public void destroy() {
71 | try {
72 | context.unregisterReceiver(mConnReceiver);
73 | } catch (IllegalArgumentException e) {
74 | }
75 |
76 | Log.i(Manager.TAG, "destroy MPCtrl");
77 |
78 | handler.getLooper().quit();
79 |
80 | notif.hideNotification();
81 | }
82 |
83 | public boolean setStatus(boolean isChecked) {
84 | if (isChecked == Config.enable)
85 | return false;
86 |
87 | Log.i(Manager.TAG, "set new status "
88 | + (isChecked ? "enable" : "disable"));
89 | Config.enable = isChecked;
90 | Config.saveStatus(context);
91 |
92 | if (isChecked)
93 | notif.showNotification();
94 | else
95 | notif.hideNotification();
96 |
97 | return true;
98 | }
99 |
100 | public boolean setSaveBattery(boolean isChecked) {
101 | if (isChecked == Config.saveBattery)
102 | return false;
103 | Config.saveBattery = isChecked;
104 | Config.saveStatus(context);
105 | return true; // nothing to do here: we need to restart app
106 | }
107 |
108 | private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
109 | @Override
110 | public void onReceive(Context context, Intent intent) {
111 | Log.i(Manager.TAG, "BroadcastReceiver " + intent);
112 | PowerManager pm = (PowerManager) context
113 | .getSystemService(Context.POWER_SERVICE);
114 | if (pm.isScreenOn())
115 | mobileDataMgr.setMobileDataActive(Config.enable);
116 | }
117 | };
118 |
119 | /*
120 | * Will not be executed in deep sleep, nice, no need to use both connections
121 | * in deep-sleep
122 | */
123 | private void initHandler() {
124 | lastTimeHandler = System.currentTimeMillis();
125 |
126 | // First check
127 | handler.post(runnableSetMobileDataActive);
128 | }
129 |
130 | /*
131 | * Ensures that the data interface and WiFi are connected at the same time.
132 | */
133 | private Runnable runnableSetMobileDataActive = new Runnable() {
134 | final long fiveSecondsMs = 5 * 1000;
135 |
136 | @Override
137 | public void run() {
138 | long nowTime = System.currentTimeMillis();
139 | // do not try keep mobile data active in deep sleep mode
140 | if (Config.enable
141 | && nowTime - lastTimeHandler < fiveSecondsMs * 2)
142 | // to not disable cellular iface
143 | mobileDataMgr.setMobileDataActive(Config.enable);
144 | lastTimeHandler = nowTime;
145 | handler.postDelayed(this, fiveSecondsMs);
146 | }
147 | };
148 | }
149 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.content.Intent;
23 | import android.os.Bundle;
24 | import android.support.v7.app.ActionBarActivity;
25 | import android.widget.CompoundButton;
26 | import android.widget.Switch;
27 | import android.widget.Toast;
28 |
29 |
30 | public class MainActivity extends ActionBarActivity {
31 |
32 | private HIPRIKeeper hipriKeeper;
33 |
34 | private Switch multiIfaceSwitch;
35 | private Switch saveBatterySwitch;
36 |
37 | @Override
38 | protected void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | setContentView(R.layout.activity_main);
41 |
42 | multiIfaceSwitch = (Switch) findViewById(R.id.switch_enable);
43 | saveBatterySwitch = (Switch) findViewById(R.id.switch_save_battery);
44 |
45 | hipriKeeper = Manager.create(getApplicationContext());
46 |
47 | multiIfaceSwitch
48 | .setOnCheckedChangeListener(onCheckedChangeListenerMultiIface);
49 | saveBatterySwitch
50 | .setOnCheckedChangeListener(onCheckedChangeListenerSaveBattery);
51 |
52 | // start a new service if needed
53 | startService(new Intent(this, MainService.class));
54 | }
55 |
56 | @Override
57 | protected void onResume() {
58 | super.onResume();
59 |
60 | setChecked();
61 | }
62 |
63 | protected void onDestroy() {
64 | super.onDestroy();
65 | Manager.destroy(getApplicationContext());
66 | }
67 |
68 |
69 | private void setChecked() {
70 | multiIfaceSwitch.setChecked(Config.enable);
71 | saveBatterySwitch.setChecked(Config.saveBattery);
72 | }
73 |
74 | private CompoundButton.OnCheckedChangeListener onCheckedChangeListenerMultiIface = new CompoundButton.OnCheckedChangeListener() {
75 | @Override
76 | public void onCheckedChanged(CompoundButton buttonView,
77 | boolean isChecked) {
78 | if (hipriKeeper.setStatus(isChecked) && !isChecked)
79 | Toast.makeText(
80 | MainActivity.this,
81 | "The second interface will be disabled in a few seconds",
82 | Toast.LENGTH_LONG).show();
83 | }
84 | };
85 |
86 | private CompoundButton.OnCheckedChangeListener onCheckedChangeListenerSaveBattery = new CompoundButton.OnCheckedChangeListener() {
87 | @Override
88 | public void onCheckedChanged(CompoundButton buttonView,
89 | boolean isChecked) {
90 | if (hipriKeeper.setSaveBattery(isChecked))
91 | Toast.makeText(
92 | MainActivity.this,
93 | "Please disconnect/reconnect cellular interface or reboot",
94 | Toast.LENGTH_LONG).show();
95 | }
96 | };
97 | }
98 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/MainService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.app.Service;
23 | import android.content.Intent;
24 | import android.os.IBinder;
25 | import android.util.Log;
26 |
27 | public class MainService extends Service {
28 |
29 | private HIPRIKeeper hipriKeeper;
30 |
31 | @Override
32 | public IBinder onBind(Intent intent) {
33 | return null;
34 | }
35 |
36 | public void onCreate() {
37 | super.onCreate();
38 | hipriKeeper = Manager.create(getApplicationContext());
39 | Log.i(Manager.TAG, "Create service");
40 | }
41 |
42 | public void onDestroy() {
43 | super.onDestroy();
44 | if (hipriKeeper != null) {
45 | Manager.destroy(getApplicationContext());
46 | Log.i(Manager.TAG, "Destroy service");
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/Manager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.content.Context;
23 | import android.util.Log;
24 |
25 | /**
26 | * Created by Matthieu Baerts on 19/04/15.
27 | */
28 | public class Manager {
29 | public static final String TAG = "hiprikeeper";
30 | public static final boolean DEBUG = false;
31 |
32 | private static HIPRIKeeper hipriKeeper = null;
33 | private static int instances = 0;
34 | private static Context usedContext;
35 |
36 | private Manager() {
37 | }
38 |
39 | /**
40 | * Create a new instance of hipriKeeper.
41 | *
42 | * @return null if you're not root.
43 | */
44 | public static HIPRIKeeper create(Context context) {
45 | if (hipriKeeper == null) {
46 | usedContext = context;
47 | hipriKeeper = new HIPRIKeeper(context);
48 | }
49 | instances++;
50 | return hipriKeeper;
51 | }
52 |
53 | /**
54 | * Destroy the instance only if we are using this context.
55 | *
56 | * @return true if the instance has really been fully destroyed
57 | */
58 | public static boolean destroy(Context context) {
59 | if (context != usedContext || hipriKeeper == null)
60 | return false;
61 | instances--;
62 | if (instances != 0) {
63 | Log.e(TAG, "destroying the non last instance");
64 | return false;
65 | }
66 | hipriKeeper.destroy();
67 | hipriKeeper = null;
68 | return true;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/MobileDataMgr.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.content.Context;
23 | import android.net.ConnectivityManager;
24 | import android.net.NetworkInfo;
25 | import android.util.Log;
26 |
27 | import java.lang.reflect.Method;
28 | import java.net.InetAddress;
29 | import java.net.UnknownHostException;
30 | import java.util.Date;
31 |
32 | /**
33 | * Created by Matthieu Baerts on 19/04/15.
34 | */
35 | public class MobileDataMgr {
36 | private final Context context;
37 | /*
38 | * We need an existing domain that nobody uses in order to have a existing
39 | * route assigned to the cellular connection. The goal is to not disable
40 | * Cellular interface when switching to a new Wi-Fi. example.org domain is
41 | * reserved by IANA, nobody will want to use it!
42 | */
43 | private static final String DEFAULT_LOOKUP_HOST = "example.org";
44 |
45 | public MobileDataMgr(Context context) {
46 | this.context = context;
47 | }
48 |
49 | private boolean isWifiConnected() {
50 | ConnectivityManager connManager = (ConnectivityManager) context
51 | .getSystemService(Context.CONNECTIVITY_SERVICE);
52 | NetworkInfo mWifi = connManager
53 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
54 | return mWifi.isConnectedOrConnecting();
55 | }
56 |
57 | /* Check whether Mobile Data has been disabled in the System Preferences */
58 | private boolean isMobileDataEnabled() {
59 | boolean mobileDataEnabled = false;
60 | ConnectivityManager cm = (ConnectivityManager) context
61 | .getSystemService(Context.CONNECTIVITY_SERVICE);
62 | try {
63 | Class> cmClass = Class.forName(cm.getClass().getName());
64 | Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
65 | method.setAccessible(true);
66 | mobileDataEnabled = (Boolean) method.invoke(cm);
67 | } catch (Exception e) {
68 | }
69 | return mobileDataEnabled;
70 | }
71 |
72 | /* Enable having WiFi and 3G/LTE enabled at the same time */
73 | public void setMobileDataActive(boolean mEnabled) {
74 | if (Manager.DEBUG)
75 | Log.d(Manager.TAG, "setMobileDataActive " + new Date());
76 |
77 | ConnectivityManager cManager = (ConnectivityManager) context
78 | .getSystemService(Context.CONNECTIVITY_SERVICE);
79 | if (isMobileDataEnabled() && isWifiConnected() && mEnabled)
80 | cManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
81 | "enableHIPRI");
82 | else
83 | cManager.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
84 | "enableHIPRI");
85 | }
86 |
87 | private static int getAddr(InetAddress inetAddress) {
88 | byte[] addrBytes;
89 | int addr;
90 | addrBytes = inetAddress.getAddress();
91 | addr = ((addrBytes[3] & 0xff) << 24) | ((addrBytes[2] & 0xff) << 16)
92 | | ((addrBytes[1] & 0xff) << 8) | (addrBytes[0] & 0xff);
93 | return addr;
94 | }
95 |
96 | /**
97 | * Transform host name in int value used by
98 | * {@link android.net.ConnectivityManager#requestRouteToHost(int, int)} method
99 | *
100 | * @param hostname
101 | * @return -1 if the host doesn't exists, elsewhere its translation to an
102 | * integer
103 | */
104 | private static int lookupHost(String hostname) {
105 | InetAddress inetAddress;
106 | try {
107 | inetAddress = InetAddress.getByName(hostname);
108 | } catch (UnknownHostException e) {
109 | return -1;
110 | }
111 | return getAddr(inetAddress);
112 | }
113 |
114 | /**
115 | * Enable mobile connection even when switching to WiFi
116 | *
117 | * Source: http://stackoverflow.com/a/4756630
118 | *
119 | * @return true for success, else false
120 | */
121 | public boolean keepMobileConnectionAlive() {
122 | ConnectivityManager connectivityManager = (ConnectivityManager) context
123 | .getSystemService(Context.CONNECTIVITY_SERVICE);
124 | if (null == connectivityManager) {
125 | Log.d(Manager.TAG,
126 | "ConnectivityManager is null, cannot try to force a mobile connection");
127 | return false;
128 | }
129 |
130 | // create a route for the specified address
131 | int hostAddress = lookupHost(DEFAULT_LOOKUP_HOST);
132 | if (-1 == hostAddress) {
133 | Log.e(Manager.TAG,
134 | "Wrong host address transformation, result was -1");
135 | return false;
136 | }
137 | // wait some time needed to connection manager for waking up
138 | try {
139 | for (int counter = 0; counter < 30; counter++) {
140 | NetworkInfo.State checkState = connectivityManager.getNetworkInfo(
141 | ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
142 | Log.d(Manager.TAG, "TYPE_MOBILE_HIPRI network state: "
143 | + checkState);
144 | if (0 == checkState.compareTo(NetworkInfo.State.CONNECTED))
145 | break;
146 | Thread.sleep(1000);
147 | }
148 | } catch (InterruptedException e) {
149 | // nothing to do
150 | }
151 | boolean resultBool = connectivityManager.requestRouteToHost(
152 | ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
153 | Log.d(Manager.TAG, "requestRouteToHost result: " + resultBool);
154 | if (!resultBool)
155 | Log.e(Manager.TAG,
156 | "Wrong requestRouteToHost result: expected true, but was false");
157 |
158 | return resultBool;
159 | }
160 | }
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/java/be/uclouvain/hiprikeeper/Notifications.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of HIPRI Keeper.
3 | *
4 | * Copyright 2015 UCLouvain - Matthieu Baerts
5 | *
6 | * This application is free software; you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation; either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | */
19 |
20 | package be.uclouvain.hiprikeeper;
21 |
22 | import android.app.Notification;
23 | import android.app.NotificationManager;
24 | import android.app.PendingIntent;
25 | import android.content.Context;
26 | import android.content.Intent;
27 |
28 | /**
29 | * Created by Matthieu Baerts on 19/04/15.
30 | */
31 | public class Notifications {
32 | private final NotificationManager mNotification;
33 | private final Context context;
34 |
35 | public Notifications(Context context) {
36 | this.context = context;
37 | mNotification = (NotificationManager) context
38 | .getSystemService(Context.NOTIFICATION_SERVICE);
39 | }
40 |
41 | public void showNotification() {
42 | Intent intent = new Intent(context, MainActivity.class);
43 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 1,
44 | intent, 0);
45 |
46 | Notification notif = new Notification.Builder(context)
47 | .setWhen(System.currentTimeMillis())
48 | .setSmallIcon(R.drawable.ic_stat_name)
49 | .setContentTitle(
50 | context.getResources().getString(
51 | R.string.notification_title))
52 | .setContentText(
53 | context.getResources().getString(
54 | R.string.notification_text))
55 | .setContentIntent(pendingIntent).build();
56 |
57 | notif.flags |= Notification.FLAG_NO_CLEAR;
58 |
59 | mNotification.notify(1, notif);
60 | }
61 |
62 | public void hideNotification() {
63 | NotificationManager mNotification = (NotificationManager) context
64 | .getSystemService(Context.NOTIFICATION_SERVICE);
65 | mNotification.cancelAll();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-hdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-hdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-hdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-hdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-hdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-hdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-mdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-mdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-mdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-mdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-mdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-mdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-xhdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-xhdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-xhdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-xhdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-xhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-xhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-xxhdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-xxhdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-xxhdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-xxhdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/drawable-xxhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
17 |
18 |
29 |
30 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | HIPRI Keeper
3 |
4 | HIPRI Enabled
5 | Click to change options
6 |
7 | Enable
8 | Save battery by allowing deep sleep mode
9 | The cellular connection will not be maintained on deep sleep if a WiFi connection is available
10 |
11 |
--------------------------------------------------------------------------------
/HIPRIKeeper/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/HIPRIKeeper/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:1.1.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/HIPRIKeeper/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: -Xmx10248m -XX:MaxPermSize=256m
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
--------------------------------------------------------------------------------
/HIPRIKeeper/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/HIPRIKeeper/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/HIPRIKeeper/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Apr 10 15:27:10 PDT 2013
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-2.2.1-all.zip
7 |
--------------------------------------------------------------------------------
/HIPRIKeeper/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 | # For Cygwin, ensure paths are in UNIX format before anything is touched.
46 | if $cygwin ; then
47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48 | fi
49 |
50 | # Attempt to set APP_HOME
51 | # Resolve links: $0 may be a link
52 | PRG="$0"
53 | # Need this for relative symlinks.
54 | while [ -h "$PRG" ] ; do
55 | ls=`ls -ld "$PRG"`
56 | link=`expr "$ls" : '.*-> \(.*\)$'`
57 | if expr "$link" : '/.*' > /dev/null; then
58 | PRG="$link"
59 | else
60 | PRG=`dirname "$PRG"`"/$link"
61 | fi
62 | done
63 | SAVED="`pwd`"
64 | cd "`dirname \"$PRG\"`/" >&-
65 | APP_HOME="`pwd -P`"
66 | cd "$SAVED" >&-
67 |
68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69 |
70 | # Determine the Java command to use to start the JVM.
71 | if [ -n "$JAVA_HOME" ] ; then
72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73 | # IBM's JDK on AIX uses strange locations for the executables
74 | JAVACMD="$JAVA_HOME/jre/sh/java"
75 | else
76 | JAVACMD="$JAVA_HOME/bin/java"
77 | fi
78 | if [ ! -x "$JAVACMD" ] ; then
79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80 |
81 | Please set the JAVA_HOME variable in your environment to match the
82 | location of your Java installation."
83 | fi
84 | else
85 | JAVACMD="java"
86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87 |
88 | Please set the JAVA_HOME variable in your environment to match the
89 | location of your Java installation."
90 | fi
91 |
92 | # Increase the maximum file descriptors if we can.
93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94 | MAX_FD_LIMIT=`ulimit -H -n`
95 | if [ $? -eq 0 ] ; then
96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97 | MAX_FD="$MAX_FD_LIMIT"
98 | fi
99 | ulimit -n $MAX_FD
100 | if [ $? -ne 0 ] ; then
101 | warn "Could not set maximum file descriptor limit: $MAX_FD"
102 | fi
103 | else
104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105 | fi
106 | fi
107 |
108 | # For Darwin, add options to specify how the application appears in the dock
109 | if $darwin; then
110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111 | fi
112 |
113 | # For Cygwin, switch paths to Windows format before running java
114 | if $cygwin ; then
115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/HIPRIKeeper/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 |
--------------------------------------------------------------------------------
/HIPRIKeeper/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/MultipathControl/.gitignore:
--------------------------------------------------------------------------------
1 | ConfigServer.java
2 |
--------------------------------------------------------------------------------
/MultipathControl/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.7
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.7
12 |
--------------------------------------------------------------------------------
/MultipathControl/AUTHORS:
--------------------------------------------------------------------------------
1 | This project has been started by Gregory Detal.
2 |
3 | The current development is now maintained by Matthieu Baerts and Quentin De Coninck.
4 |
5 | Thanks to Carmen Alvarez for his Network-Monitor project! It was useful for the logging part.
6 | https://github.com/caarmen/network-monitor/ (Licensed under the Apache License, Version 2.0)
--------------------------------------------------------------------------------
/MultipathControl/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
25 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
40 |
41 |
42 |
43 |
44 |
45 |
48 |
49 |
52 |
53 |
54 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/MultipathControl/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/MultipathControl/ic_launcher-web.png
--------------------------------------------------------------------------------
/MultipathControl/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/MultipathControl/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/MultipathControl/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
22 | -keep class * extends java.util.ListResourceBundle {
23 | protected Object[][] getContents();
24 | }
25 |
26 | -keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
27 | public static final *** NULL;
28 | }
29 |
30 | -keepnames @com.google.android.gms.common.annotation.KeepName class *
31 | -keepclassmembernames class * {
32 | @com.google.android.gms.common.annotation.KeepName *;
33 | }
34 |
35 | -keepnames class * implements android.os.Parcelable {
36 | public static final ** CREATOR;
37 | }
--------------------------------------------------------------------------------
/MultipathControl/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/MultipathControl/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultipathControl/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/MultipathControl/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultipathControl/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/MultipathControl/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultipathControl/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MPTCP-smartphone-thesis/MultipathControl/6fa8658d1af373af72be1e818b323849e29490a6/MultipathControl/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/MultipathControl/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
19 |
20 |
28 |
29 |
38 |
39 |
47 |
48 |
57 |
58 |
66 |
67 |
76 |
77 |
85 |
86 |
94 |
95 |
103 |
104 |
112 |
113 |
121 |
122 |
131 |
132 |
--------------------------------------------------------------------------------
/MultipathControl/res/layout/tcp_cc.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/MultipathControl/res/layout/tcp_cc_list_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
--------------------------------------------------------------------------------
/MultipathControl/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/MultipathControl/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/MultipathControl/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
--------------------------------------------------------------------------------
/MultipathControl/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/MultipathControl/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/MultipathControl/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 | 64dp
9 |
10 |
11 |
--------------------------------------------------------------------------------
/MultipathControl/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/MultipathControl/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Multipath Control
5 | Settings
6 | Enable multi-interface
7 | Default route via cellular
8 | Set cellular as backup
9 | Patched version of iproute is needed
10 | Save battery by allowing deep sleep mode
11 | The cellular connection will not be maintained all the time. Then when switching to a new Wi-Fi router, the cellular connection will be stopped for a few micro seconds but it\'s supported by MPTCP
12 | Enable IPv6 support
13 | MPTCP and this application support IPv6 but not ShadowSocks proxy
14 | Save power GPS
15 | Send log files now
16 | Multipath Enabled
17 | Click to change options
18 | TCP CC Algorithms
19 | Track: get data on changes
20 | Track: get data each sec
21 |
22 |
--------------------------------------------------------------------------------
/MultipathControl/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/MPCtrl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol;
22 |
23 | import java.net.NetworkInterface;
24 | import java.util.List;
25 |
26 | import android.content.BroadcastReceiver;
27 | import android.content.Context;
28 | import android.content.Intent;
29 | import android.content.IntentFilter;
30 | import android.net.ConnectivityManager;
31 | import android.os.Handler;
32 | import android.os.PowerManager;
33 | import android.util.Log;
34 | import android.widget.Toast;
35 | import be.uclouvain.multipathcontrol.global.Config;
36 | import be.uclouvain.multipathcontrol.global.ConfigServer;
37 | import be.uclouvain.multipathcontrol.global.Manager;
38 | import be.uclouvain.multipathcontrol.ifaces.IPRoute;
39 | import be.uclouvain.multipathcontrol.ifaces.MobileDataMgr;
40 | import be.uclouvain.multipathcontrol.stats.JSONSender;
41 | import be.uclouvain.multipathcontrol.stats.SaveDataApp;
42 | import be.uclouvain.multipathcontrol.stats.SaveDataHandover;
43 | import be.uclouvain.multipathcontrol.system.Cmd;
44 | import be.uclouvain.multipathcontrol.system.IPRouteUtils;
45 | import be.uclouvain.multipathcontrol.ui.Notifications;
46 |
47 | public class MPCtrl {
48 |
49 | private final Context context;
50 | private final Notifications notif;
51 | private final MobileDataMgr mobileDataMgr;
52 | private final Handler handler;
53 | private final IPRoute iproute;
54 | private static long lastTimeHandler;
55 |
56 | private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
57 | @Override
58 | public void onReceive(Context context, Intent intent) {
59 | Log.i(Manager.TAG, "BroadcastReceiver " + intent);
60 | PowerManager pm = (PowerManager) context
61 | .getSystemService(Context.POWER_SERVICE);
62 | if (pm.isScreenOn())
63 | mobileDataMgr.setMobileDataActive(Config.mEnabled);
64 | if (iproute.monitorInterfaces() && Config.tracking)
65 | new SaveDataHandover(context);
66 | }
67 | };
68 |
69 | public MPCtrl(Context context) {
70 | this.context = context;
71 |
72 | // to be sure that all connections will be managed by the proxy
73 | restartIFaces();
74 |
75 | Config.getDefaultConfig(context);
76 | notif = new Notifications(context);
77 | mobileDataMgr = new MobileDataMgr(context);
78 | iproute = new IPRoute(mobileDataMgr);
79 | Log.i(Manager.TAG, "new MPCtrl");
80 |
81 | handler = new Handler();
82 | initHandler();
83 |
84 | /*
85 | * mConnReceiver will be called each time a change of connectivity
86 | * happen
87 | */
88 | context.registerReceiver(mConnReceiver, new IntentFilter(
89 | ConnectivityManager.CONNECTIVITY_ACTION));
90 |
91 | if (Config.mEnabled)
92 | notif.showNotification();
93 |
94 | // Log
95 | if (Config.tracking) {
96 | new SaveDataApp(context);
97 | new SaveDataHandover(context);
98 | }
99 | }
100 |
101 | public void destroy() {
102 | try {
103 | context.unregisterReceiver(mConnReceiver);
104 | } catch (IllegalArgumentException e) {
105 | }
106 |
107 | Log.i(Manager.TAG, "destroy MPCtrl");
108 |
109 | handler.getLooper().quit();
110 |
111 | notif.hideNotification();
112 | }
113 |
114 | public boolean setStatus(boolean isChecked) {
115 | if (isChecked == Config.mEnabled)
116 | return false;
117 |
118 | Log.i(Manager.TAG, "set new status "
119 | + (isChecked ? "enable" : "disable"));
120 | Config.mEnabled = isChecked;
121 | Config.saveStatus(context);
122 |
123 | if (isChecked) {
124 | notif.showNotification();
125 | if (iproute.monitorInterfaces() && Config.tracking)
126 | new SaveDataHandover(context);
127 | } else {
128 | notif.hideNotification();
129 | }
130 |
131 | return true;
132 | }
133 |
134 | public boolean setDefaultData(boolean isChecked) {
135 | if (isChecked == Config.defaultRouteData)
136 | return false;
137 | Config.defaultRouteData = isChecked;
138 | Config.saveStatus(context);
139 |
140 | return IPRouteUtils.setDefaultRoute();
141 | }
142 |
143 | public boolean setDataBackup(boolean isChecked) {
144 | if (isChecked == Config.dataBackup)
145 | return false;
146 | Config.dataBackup = isChecked;
147 | Config.saveStatus(context);
148 |
149 | return IPRouteUtils.setDataBackup();
150 | }
151 |
152 | public boolean setSaveBattery(boolean isChecked) {
153 | if (isChecked == Config.saveBattery)
154 | return false;
155 | Config.saveBattery = isChecked;
156 | Config.saveStatus(context);
157 | return true; // nothing to do here: we need to restart app
158 | }
159 |
160 | public boolean setSavePowerGPS(boolean isChecked) {
161 | if (isChecked == Config.savePowerGPS)
162 | return false;
163 | Config.savePowerGPS = isChecked;
164 | Config.saveStatus(context);
165 | SaveDataHandover.savePowerGPS(isChecked);
166 | return true;
167 | }
168 |
169 | public boolean setTracking(boolean isChecked) {
170 | if (isChecked == Config.tracking)
171 | return false;
172 | Config.tracking = isChecked;
173 | Config.saveStatus(context);
174 | // we also need to know when it has been disabled
175 | if (!Config.tracking)
176 | new SaveDataApp(context);
177 | return true;
178 | }
179 |
180 | public boolean setTrackingSec(boolean isChecked) {
181 | if (isChecked == Config.trackingSec)
182 | return false;
183 | Config.trackingSec = isChecked;
184 | if (Config.trackingSec) {
185 | Config.mobileDataActiveTime = 1000;
186 | handler.post(runnableTracking);
187 | }
188 | else {
189 | Config.mobileDataActiveTime = 5000;
190 | Toast.makeText(context, "Stop tracking, sending data",
191 | Toast.LENGTH_LONG).show();
192 | JSONSender.sendAll(context);
193 | }
194 | return true;
195 | }
196 |
197 | public void displayWarningIfNoHostname(boolean isChecked) {
198 | if (isChecked && ConfigServer.hostname.isEmpty())
199 | Toast.makeText(
200 | context,
201 | "Collecting data but no hostname defined. Data will be "
202 | + "stored in the preferences of this app but never"
203 | + " sent to a server.",
204 | Toast.LENGTH_LONG).show();
205 | }
206 |
207 | /**
208 | * Restart all active interfaces in order to be sure that all connections
209 | * will be managed by the Proxy and use the right MPTCP options
210 | */
211 | private void restartIFaces() {
212 | List activeIfaces = IPRouteUtils.getActiveIfaces();
213 | if (activeIfaces == null || activeIfaces.isEmpty())
214 | return;
215 |
216 | for (NetworkInterface iface : activeIfaces) {
217 | String ifaceName = iface.getName();
218 | Log.d(Manager.TAG, "restart iface: " + ifaceName);
219 | try {
220 | Cmd.runAsRoot("ip link set " + ifaceName + " down").wait();
221 | } catch (Exception e) {
222 | Log.w(Manager.TAG, "Error when disabling " + ifaceName + ": "
223 | + e.getMessage());
224 | }
225 | try {
226 | Cmd.runAsRoot("ip link set " + ifaceName + " up");
227 | } catch (Exception e) {
228 | Log.w(Manager.TAG, "Error when disabling " + ifaceName + ": "
229 | + e.getMessage());
230 | }
231 | }
232 | }
233 |
234 | // Will not be executed in deep sleep, nice, no need to use both connections
235 | // in deep-sleep
236 | private void initHandler() {
237 | lastTimeHandler = System.currentTimeMillis();
238 |
239 | // First check
240 | handler.post(runnableSetMobileDataActive);
241 | handler.postDelayed(runnableSendData, 5 * 1000 * 60); // 5min
242 | }
243 |
244 | /*
245 | * Ensures that the data interface and WiFi are connected at the same time.
246 | */
247 | private Runnable runnableSetMobileDataActive = new Runnable() {
248 | @Override
249 | public void run() {
250 | long nowTime = System.currentTimeMillis();
251 | // do not try keep mobile data active in deep sleep mode
252 | if (Config.mEnabled
253 | && nowTime - lastTimeHandler < Config.mobileDataActiveTime * 2)
254 | // to not disable cellular iface
255 | mobileDataMgr.setMobileDataActive(Config.mEnabled);
256 | lastTimeHandler = nowTime;
257 | handler.postDelayed(this, Config.mobileDataActiveTime);
258 | }
259 | };
260 |
261 | private Runnable runnableSendData = new Runnable() {
262 | final long oneHourMs = 1000 * 60 * 60;
263 |
264 | @Override
265 | public void run() {
266 | Log.d(Manager.TAG, "Schedule: new upload");
267 | JSONSender.sendAll(context);
268 | handler.postDelayed(this, oneHourMs);
269 | }
270 | };
271 |
272 | private Runnable runnableTracking = new Runnable() {
273 | @Override
274 | public void run() {
275 | new SaveDataHandover(context, true);
276 | if (Config.trackingSec) // continue if enable
277 | handler.postDelayed(this, 1000);
278 | }
279 | };
280 | }
281 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.activities;
22 |
23 | import android.app.Activity;
24 | import android.content.Intent;
25 | import android.os.Bundle;
26 | import android.util.Log;
27 | import android.view.View;
28 | import android.view.View.OnClickListener;
29 | import android.widget.Button;
30 | import android.widget.CompoundButton;
31 | import android.widget.CompoundButton.OnCheckedChangeListener;
32 | import android.widget.Switch;
33 | import android.widget.Toast;
34 | import be.uclouvain.multipathcontrol.MPCtrl;
35 | import be.uclouvain.multipathcontrol.R;
36 | import be.uclouvain.multipathcontrol.global.Config;
37 | import be.uclouvain.multipathcontrol.global.Manager;
38 | import be.uclouvain.multipathcontrol.services.MainService;
39 | import be.uclouvain.multipathcontrol.stats.JSONSender;
40 | import be.uclouvain.multipathcontrol.system.Sysctl;
41 |
42 | public class MainActivity extends Activity {
43 |
44 | private MPCtrl mpctrl;
45 | private Switch multiIfaceSwitch;
46 | private Switch defaultDataSwitch;
47 | private Switch dataBackupSwitch;
48 | private Switch saveBatterySwitch;
49 | private Switch ipv6Switch;
50 | private Switch savePowerGPSSwitch;
51 | private Switch trackingSwitch;
52 | private Switch trackingSecSwitch;
53 | private Button tcpCCButton;
54 |
55 | @Override
56 | protected void onCreate(Bundle savedInstanceState) {
57 | super.onCreate(savedInstanceState);
58 | setContentView(R.layout.main);
59 |
60 | multiIfaceSwitch = (Switch) findViewById(R.id.switch_multiiface);
61 | defaultDataSwitch = (Switch) findViewById(R.id.switch_default_data);
62 | dataBackupSwitch = (Switch) findViewById(R.id.switch_data_backup);
63 | saveBatterySwitch = (Switch) findViewById(R.id.switch_save_battery);
64 | ipv6Switch = (Switch) findViewById(R.id.switch_ipv6);
65 | savePowerGPSSwitch = (Switch) findViewById(R.id.switch_save_power_gps);
66 | trackingSwitch = (Switch) findViewById(R.id.switch_tracking);
67 | trackingSecSwitch = (Switch) findViewById(R.id.switch_tracking_sec);
68 | tcpCCButton = (Button) findViewById(R.id.button_tcp_cc);
69 |
70 | mpctrl = Manager.create(getApplicationContext());
71 | if (mpctrl == null) {
72 | Toast.makeText(this, "It seems this is not a rooted device",
73 | Toast.LENGTH_LONG).show();
74 | moveTaskToBack(true);
75 | return;
76 | }
77 |
78 | // do that now, to avoid useless call to onCheckedChangeListerner
79 | setChecked();
80 | multiIfaceSwitch
81 | .setOnCheckedChangeListener(onCheckedChangeListernerMultiIface);
82 | defaultDataSwitch
83 | .setOnCheckedChangeListener(onCheckedChangeListernerDefaultData);
84 | dataBackupSwitch
85 | .setOnCheckedChangeListener(onCheckedChangeListernerDataBackup);
86 | saveBatterySwitch
87 | .setOnCheckedChangeListener(onCheckedChangeListernerSaveBattery);
88 | ipv6Switch.setOnCheckedChangeListener(onCheckedChangeListernerIPv6);
89 | savePowerGPSSwitch
90 | .setOnCheckedChangeListener(onCheckedChangeListernerSavePowerGPS);
91 | trackingSwitch
92 | .setOnCheckedChangeListener(onCheckedChangeListernerTracking);
93 | trackingSecSwitch
94 | .setOnCheckedChangeListener(onCheckedChangeListernerTrackingSec);
95 | tcpCCButton.setOnClickListener(onClickListenerTcpCC);
96 |
97 | Button testButton = (Button) findViewById(R.id.button_send_data);
98 | testButton.setOnClickListener(onClickListenerSend);
99 |
100 |
101 | // start a new service if needed
102 | startService(new Intent(this, MainService.class));
103 | }
104 |
105 | @Override
106 | protected void onResume() {
107 | super.onResume();
108 |
109 | Config.updateDynamicConfig();
110 | setChecked();
111 | }
112 |
113 | protected void onDestroy() {
114 | super.onDestroy();
115 | Manager.destroy(getApplicationContext());
116 | }
117 |
118 | private void setChecked() {
119 | multiIfaceSwitch.setChecked(Config.mEnabled);
120 | defaultDataSwitch.setChecked(Config.defaultRouteData);
121 | dataBackupSwitch.setChecked(Config.dataBackup);
122 | saveBatterySwitch.setChecked(Config.saveBattery);
123 | ipv6Switch.setChecked(Config.ipv6);
124 | savePowerGPSSwitch.setChecked(Config.savePowerGPS);
125 | trackingSwitch.setChecked(Config.tracking);
126 | trackingSecSwitch.setChecked(Config.trackingSec);
127 | tcpCCButton.setText(getText(R.string.button_tcp_cc) + ": "
128 | + Config.tcpcc);
129 | }
130 |
131 | private OnCheckedChangeListener onCheckedChangeListernerMultiIface = new OnCheckedChangeListener() {
132 | @Override
133 | public void onCheckedChanged(CompoundButton buttonView,
134 | boolean isChecked) {
135 | if (mpctrl.setStatus(isChecked) && !isChecked)
136 | Toast.makeText(
137 | MainActivity.this,
138 | "The second interface will be disabled in a few seconds",
139 | Toast.LENGTH_LONG).show();
140 | }
141 | };
142 |
143 | private OnCheckedChangeListener onCheckedChangeListernerDefaultData = new OnCheckedChangeListener() {
144 | @Override
145 | public void onCheckedChanged(CompoundButton buttonView,
146 | boolean isChecked) {
147 | mpctrl.setDefaultData(isChecked);
148 | }
149 | };
150 |
151 | private OnCheckedChangeListener onCheckedChangeListernerDataBackup = new OnCheckedChangeListener() {
152 | @Override
153 | public void onCheckedChanged(CompoundButton buttonView,
154 | boolean isChecked) {
155 | mpctrl.setDataBackup(isChecked);
156 | }
157 | };
158 |
159 | private OnCheckedChangeListener onCheckedChangeListernerSaveBattery = new OnCheckedChangeListener() {
160 | @Override
161 | public void onCheckedChanged(CompoundButton buttonView,
162 | boolean isChecked) {
163 | if (mpctrl.setSaveBattery(isChecked))
164 | Toast.makeText(
165 | MainActivity.this,
166 | "Please disconnect/reconnect cellular interface or reboot",
167 | Toast.LENGTH_LONG).show();
168 | }
169 | };
170 |
171 | private OnCheckedChangeListener onCheckedChangeListernerIPv6 = new OnCheckedChangeListener() {
172 | @Override
173 | public void onCheckedChanged(CompoundButton buttonView,
174 | boolean isChecked) {
175 | if (Config.ipv6 != isChecked && Sysctl.setIPv6(isChecked)) {
176 | Config.ipv6 = isChecked;
177 | Config.saveStatus(getApplicationContext());
178 | } else
179 | Toast.makeText(MainActivity.this,
180 | "Not able to change IPv6 settings",
181 | Toast.LENGTH_LONG).show();
182 | }
183 | };
184 |
185 | private OnCheckedChangeListener onCheckedChangeListernerSavePowerGPS = new OnCheckedChangeListener() {
186 | @Override
187 | public void onCheckedChanged(CompoundButton buttonView,
188 | boolean isChecked) {
189 | mpctrl.setSavePowerGPS(isChecked);
190 | }
191 | };
192 |
193 | private OnCheckedChangeListener onCheckedChangeListernerTracking = new OnCheckedChangeListener() {
194 | @Override
195 | public void onCheckedChanged(CompoundButton buttonView,
196 | boolean isChecked) {
197 | if (mpctrl.setTracking(isChecked))
198 | mpctrl.displayWarningIfNoHostname(isChecked);
199 | }
200 | };
201 |
202 | private OnCheckedChangeListener onCheckedChangeListernerTrackingSec = new OnCheckedChangeListener() {
203 | @Override
204 | public void onCheckedChanged(CompoundButton buttonView,
205 | boolean isChecked) {
206 | if (mpctrl.setTrackingSec(isChecked)) {
207 | // track with better accuracy
208 | savePowerGPSSwitch.setChecked(!isChecked);
209 | mpctrl.displayWarningIfNoHostname(isChecked);
210 | }
211 | }
212 | };
213 |
214 | private OnClickListener onClickListenerTcpCC = new OnClickListener() {
215 | @Override
216 | public void onClick(View v) {
217 | Intent intent = new Intent(MainActivity.this, TCPCCActivity.class);
218 | startActivity(intent);
219 | }
220 | };
221 |
222 | private OnClickListener onClickListenerSend = new OnClickListener() {
223 | @Override
224 | public void onClick(View v) {
225 | Log.d(Manager.TAG, "Send data from button");
226 | JSONSender.sendAll(getApplicationContext());
227 | }
228 | };
229 | }
230 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/activities/TCPCCActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.activities;
22 |
23 | import android.app.ListActivity;
24 | import android.os.Bundle;
25 | import android.view.View;
26 | import android.widget.ArrayAdapter;
27 | import android.widget.ListView;
28 | import android.widget.Toast;
29 | import be.uclouvain.multipathcontrol.global.Config;
30 | import be.uclouvain.multipathcontrol.system.Sysctl;
31 |
32 | public class TCPCCActivity extends ListActivity {
33 | public void onCreate(Bundle icicle) {
34 | super.onCreate(icicle);
35 | ArrayAdapter adapter = new ArrayAdapter(this,
36 | android.R.layout.simple_list_item_1, Sysctl.getAvailableCC());
37 | setListAdapter(adapter);
38 | setSelected(Config.tcpcc);
39 | }
40 |
41 | private void setSelected(String item) {
42 | getActionBar().setTitle("Selected: " + item);
43 | }
44 |
45 | @Override
46 | protected void onListItemClick(ListView l, View v, int position, long id) {
47 | String item = (String) getListAdapter().getItem(position);
48 | if (!Config.tcpcc.equals(item) && Sysctl.setCC(item)) {
49 | setSelected(item);
50 | Config.tcpcc = item;
51 | Config.saveStatus(getApplicationContext());
52 | } else
53 | Toast.makeText(TCPCCActivity.this, "Not able to set " + item,
54 | Toast.LENGTH_LONG).show();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/global/Config.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.global;
22 |
23 | import android.content.Context;
24 | import android.content.SharedPreferences;
25 | import be.uclouvain.multipathcontrol.stats.SaveDataApp;
26 | import be.uclouvain.multipathcontrol.system.Sysctl;
27 |
28 | public class Config {
29 |
30 | public static final String PREFS_NAME = "MultipathControl";
31 | public static final String PREFS_STATUS = "enableMultiInterfaces";
32 | public static final String PREFS_DEFAULT_DATA = "defaultData";
33 | public static final String PREFS_DATA_BACKUP = "dataBackup";
34 | public static final String PREFS_SAVE_BATTERY = "saveBattery";
35 | public static final String PREFS_IPV6 = "ipv6";
36 | public static final String PREFS_SAVE_POWER_GPS = "savePowerGPS";
37 | public static final String PREFS_TRACKING = "tracking";
38 | public static final String PREFS_TCPCC = "tcpcc";
39 | public static final String PREFS_STATS_SET = "statsSet";
40 |
41 | public static boolean mEnabled;
42 | public static boolean defaultRouteData;
43 | public static boolean dataBackup;
44 | public static boolean saveBattery;
45 | public static boolean ipv6;
46 | public static boolean savePowerGPS;
47 | public static boolean tracking;
48 | public static String tcpcc;
49 |
50 | public static int mobileDataActiveTime = 5000;
51 | public static boolean trackingSec = false;
52 |
53 | private Config() {
54 | }
55 |
56 | public static void getDefaultConfig(Context context) {
57 | SharedPreferences settings = context.getSharedPreferences(PREFS_NAME,
58 | Context.MODE_PRIVATE);
59 | mEnabled = settings.getBoolean(PREFS_STATUS, true);
60 | defaultRouteData = settings.getBoolean(PREFS_DEFAULT_DATA, false);
61 | dataBackup = settings.getBoolean(PREFS_DATA_BACKUP, false);
62 | saveBattery = settings.getBoolean(PREFS_SAVE_BATTERY, true);
63 | savePowerGPS = settings.getBoolean(PREFS_SAVE_POWER_GPS, true);
64 | // false by default if no hostname is defined (where to send data)
65 | tracking = settings.getBoolean(PREFS_TRACKING,
66 | !ConfigServer.hostname.isEmpty());
67 |
68 | // Dynamic
69 | ipv6 = settings.getBoolean(PREFS_IPV6, false);
70 | if (ipv6 != Sysctl.getIPv6())
71 | Sysctl.setIPv6(ipv6);
72 |
73 | tcpcc = settings.getString(PREFS_TCPCC, "lia");
74 | if (!tcpcc.equals(Sysctl.getCC()))
75 | Sysctl.setCC(tcpcc);
76 | }
77 |
78 | public static void updateDynamicConfig() {
79 | ipv6 = Sysctl.getIPv6();
80 | tcpcc = Sysctl.getCC();
81 | }
82 |
83 | public static void saveStatus(Context context) {
84 | if (tracking)
85 | new SaveDataApp(context);
86 |
87 | SharedPreferences settings = context.getSharedPreferences(PREFS_NAME,
88 | Context.MODE_PRIVATE);
89 | SharedPreferences.Editor editor = settings.edit();
90 | editor.putBoolean(PREFS_STATUS, mEnabled);
91 | editor.putBoolean(PREFS_DEFAULT_DATA, defaultRouteData);
92 | editor.putBoolean(PREFS_DATA_BACKUP, dataBackup);
93 | editor.putBoolean(PREFS_SAVE_BATTERY, saveBattery);
94 | editor.putBoolean(PREFS_IPV6, ipv6);
95 | editor.putBoolean(PREFS_SAVE_POWER_GPS, savePowerGPS);
96 | editor.putBoolean(PREFS_TRACKING, tracking);
97 | editor.putString(PREFS_TCPCC, tcpcc);
98 | editor.apply();
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/global/ConfigServerExample.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.global;
22 |
23 | public final class ConfigServerExample {
24 | private ConfigServerExample() {
25 | }
26 |
27 | public static final String hostname = "example.org";
28 | public static final int port = 0;
29 | public static final String username = "user";
30 | public static final String password = "password";
31 | }
32 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/global/Manager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.global;
22 |
23 | import java.io.File;
24 |
25 | import android.content.Context;
26 | import android.util.Log;
27 | import be.uclouvain.multipathcontrol.MPCtrl;
28 |
29 | public class Manager {
30 | public static final String TAG = "mpctrl";
31 | public static final boolean DEBUG = false;
32 |
33 | private static MPCtrl mpctrl = null;
34 | private static int instances = 0;
35 | private static Context usedContext;
36 |
37 | private Manager() {
38 | }
39 |
40 | private static boolean checkRoot() {
41 | return new File("/system/xbin/su").canExecute();
42 | }
43 |
44 | /**
45 | * Create a new instance of MPCtrl.
46 | *
47 | * @return null if you're not root.
48 | */
49 | public static MPCtrl create(Context context) {
50 | if (mpctrl == null) {
51 | if (!checkRoot()) {
52 | Log.e(TAG, "It seems it's not a rooted device...");
53 | return null;
54 | }
55 | usedContext = context;
56 | mpctrl = new MPCtrl(context);
57 | }
58 | instances++;
59 | return mpctrl;
60 | }
61 |
62 | /**
63 | * Destroy the instance only if we are using this context.
64 | *
65 | * @return true if the instance has really been fully destroyed
66 | */
67 | public static boolean destroy(Context context) {
68 | if (context != usedContext || mpctrl == null)
69 | return false;
70 | instances--;
71 | if (instances != 0) {
72 | Log.e(TAG, "destroying the non last instance");
73 | return false;
74 | }
75 | mpctrl.destroy();
76 | mpctrl = null;
77 | return true;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/ifaces/IPRoute.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.ifaces;
22 |
23 | import java.net.InetAddress;
24 | import java.net.InterfaceAddress;
25 | import java.net.NetworkInterface;
26 | import java.net.SocketException;
27 | import java.net.UnknownHostException;
28 | import java.util.Collections;
29 | import java.util.HashMap;
30 |
31 | import android.util.Log;
32 | import be.uclouvain.multipathcontrol.global.Config;
33 | import be.uclouvain.multipathcontrol.global.Manager;
34 | import be.uclouvain.multipathcontrol.system.Cmd;
35 | import be.uclouvain.multipathcontrol.system.IPRouteUtils;
36 | import be.uclouvain.multipathcontrol.system.Sysctl;
37 |
38 | public class IPRoute {
39 |
40 | private final MobileDataMgr mobileDataMgr;
41 |
42 | private HashMap mIntfState;
43 |
44 | public IPRoute(MobileDataMgr mobileDataMgr) {
45 | mIntfState = new HashMap();
46 | this.mobileDataMgr = mobileDataMgr;
47 | monitorInterfaces();
48 | }
49 |
50 | /* Add Policy routing for interface */
51 | private void setupRule(NetworkInterface iface, boolean update) {
52 | int table = IPRouteUtils.mapIfaceToTable(iface);
53 |
54 | if (update)
55 | IPRouteUtils.resetRule(iface);
56 |
57 | if (iface.getInterfaceAddresses().isEmpty())
58 | return;
59 |
60 | for (InterfaceAddress intfAddr : iface.getInterfaceAddresses()) {
61 | InetAddress addr = intfAddr.getAddress();
62 | int prefix = intfAddr.getNetworkPrefixLength();
63 | InetAddress subnet;
64 | String gateway = IPRouteUtils.getGateway(iface);
65 |
66 | if (gateway == null)
67 | continue;
68 | gateway = IPRouteUtils.removeScope(gateway);
69 |
70 | try {
71 | subnet = IPRouteUtils.toSubnet(addr, prefix);
72 | } catch (UnknownHostException e) {
73 | continue;
74 | }
75 |
76 | if (addr.isLinkLocalAddress())
77 | continue;
78 |
79 | String hostAddr = IPRouteUtils.removeScope(addr.getHostAddress());
80 | String subnetAddr = IPRouteUtils.removeScope(subnet
81 | .getHostAddress());
82 | if (hostAddr == null || subnetAddr == null) {
83 | Log.w(Manager.TAG, "hostAddr and/or subnetAddr is null");
84 | continue;
85 | }
86 |
87 | try {
88 | Cmd.runAsRoot(new String[] {
89 | "ip " + IPRouteUtils.getIPVersion(hostAddr)
90 | + " rule add from " + hostAddr + " table "
91 | + table,
92 | "ip " + IPRouteUtils.getIPVersion(subnetAddr)
93 | + " route add " + subnetAddr + "/" + prefix
94 | + " dev " + iface.getName()
95 | + " scope link table " + table,
96 | "ip " + IPRouteUtils.getIPVersion(gateway)
97 | + " route add default via " + gateway + " dev "
98 | + iface.getName() + " table " + table, });
99 | if (IPRouteUtils.isMobile(iface)) {
100 | if (Config.defaultRouteData)
101 | IPRouteUtils.setDefaultRoute(iface.getName(), gateway,
102 | false);
103 | if (Config.dataBackup)
104 | Cmd.runAsRoot("ip link set dev " + iface.getName()
105 | + " multipath backup");
106 | mobileDataMgr.keepMobileConnectionAlive();
107 | }
108 | } catch (Exception e) {
109 | }
110 | if (!Config.ipv6)
111 | Sysctl.setIPv6(false, iface.getName());
112 | }
113 |
114 | }
115 |
116 | public boolean monitorInterfaces() {
117 | boolean update = false;
118 | try {
119 | for (NetworkInterface iface : Collections.list(NetworkInterface
120 | .getNetworkInterfaces())) {
121 | int addrs = Config.mEnabled ? iface.getInterfaceAddresses()
122 | .hashCode() : 1;
123 | String name = iface.getName();
124 |
125 | if (iface.isLoopback())
126 | continue;
127 |
128 | if (!mIntfState.containsKey(name)) {
129 | if (addrs != 1) /* hashcode of an empty List is 1 */
130 | setupRule(iface, false);
131 | Log.i(Manager.TAG, "New monitor " + name + " addrs: "
132 | + addrs);
133 | mIntfState.put(name, addrs);
134 | update = true;
135 | continue;
136 | }
137 |
138 | if (addrs != mIntfState.get(name)) {
139 | Log.i(Manager.TAG, "New addrs for " + name + " addrs: "
140 | + addrs);
141 | setupRule(iface, true);
142 | mIntfState.put(name, addrs);
143 | update = true;
144 | }
145 | }
146 | } catch (SocketException e) {
147 | }
148 |
149 | // if WLan iface has been modified, default route will be wrong
150 | if (update && Config.defaultRouteData)
151 | IPRouteUtils.setDefaultRoute();
152 |
153 | return update;
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/ifaces/MobileDataMgr.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.ifaces;
22 |
23 | import java.lang.reflect.Method;
24 | import java.net.InetAddress;
25 | import java.net.UnknownHostException;
26 | import java.util.Date;
27 |
28 | import android.content.Context;
29 | import android.net.ConnectivityManager;
30 | import android.net.NetworkInfo;
31 | import android.net.NetworkInfo.State;
32 | import android.util.Log;
33 | import be.uclouvain.multipathcontrol.global.Manager;
34 |
35 | public class MobileDataMgr {
36 |
37 | private final Context context;
38 | /*
39 | * We need an existing domain that nobody uses in order to have a existing
40 | * route assigned to the cellular connection. The goal is to not disable
41 | * Cellular interface when switching to a new Wi-Fi. example.org domain is
42 | * reserved by IANA, nobody will want to use it!
43 | */
44 | private static final String DEFAULT_LOOKUP_HOST = "example.org";
45 |
46 | public MobileDataMgr(Context context) {
47 | this.context = context;
48 | }
49 |
50 | private boolean isWifiConnected() {
51 | ConnectivityManager connManager = (ConnectivityManager) context
52 | .getSystemService(Context.CONNECTIVITY_SERVICE);
53 | NetworkInfo mWifi = connManager
54 | .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
55 | return mWifi.isConnectedOrConnecting();
56 | }
57 |
58 | /* Check whether Mobile Data has been disabled in the System Preferences */
59 | private boolean isMobileDataEnabled() {
60 | boolean mobileDataEnabled = false;
61 | ConnectivityManager cm = (ConnectivityManager) context
62 | .getSystemService(Context.CONNECTIVITY_SERVICE);
63 | try {
64 | Class> cmClass = Class.forName(cm.getClass().getName());
65 | Method method = cmClass.getDeclaredMethod("getMobileDataEnabled");
66 | method.setAccessible(true);
67 | mobileDataEnabled = (Boolean) method.invoke(cm);
68 | } catch (Exception e) {
69 | }
70 | return mobileDataEnabled;
71 | }
72 |
73 | /* Enable having WiFi and 3G/LTE enabled at the same time */
74 | public void setMobileDataActive(boolean mEnabled) {
75 | if (Manager.DEBUG)
76 | Log.d(Manager.TAG, "setMobileDataActive " + new Date());
77 |
78 | ConnectivityManager cManager = (ConnectivityManager) context
79 | .getSystemService(Context.CONNECTIVITY_SERVICE);
80 | if (isMobileDataEnabled() && isWifiConnected() && mEnabled)
81 | cManager.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
82 | "enableHIPRI");
83 | else
84 | cManager.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
85 | "enableHIPRI");
86 | }
87 |
88 | private static int getAddr(InetAddress inetAddress) {
89 | byte[] addrBytes;
90 | int addr;
91 | addrBytes = inetAddress.getAddress();
92 | addr = ((addrBytes[3] & 0xff) << 24) | ((addrBytes[2] & 0xff) << 16)
93 | | ((addrBytes[1] & 0xff) << 8) | (addrBytes[0] & 0xff);
94 | return addr;
95 | }
96 |
97 | /**
98 | * Transform host name in int value used by
99 | * {@link ConnectivityManager.requestRouteToHost} method
100 | *
101 | * @param hostname
102 | * @return -1 if the host doesn't exists, elsewhere its translation to an
103 | * integer
104 | */
105 | private static int lookupHost(String hostname) {
106 | InetAddress inetAddress;
107 | try {
108 | inetAddress = InetAddress.getByName(hostname);
109 | } catch (UnknownHostException e) {
110 | return -1;
111 | }
112 | return getAddr(inetAddress);
113 | }
114 |
115 | /**
116 | * Enable mobile connection even when switching to WiFi
117 | *
118 | * Source: http://stackoverflow.com/a/4756630
119 | *
120 | * @param address
121 | * the address to enable
122 | * @return true for success, else false
123 | */
124 | public boolean keepMobileConnectionAlive() {
125 | ConnectivityManager connectivityManager = (ConnectivityManager) context
126 | .getSystemService(Context.CONNECTIVITY_SERVICE);
127 | if (null == connectivityManager) {
128 | Log.d(Manager.TAG,
129 | "ConnectivityManager is null, cannot try to force a mobile connection");
130 | return false;
131 | }
132 |
133 | // create a route for the specified address
134 | int hostAddress = lookupHost(DEFAULT_LOOKUP_HOST);
135 | if (-1 == hostAddress) {
136 | Log.e(Manager.TAG,
137 | "Wrong host address transformation, result was -1");
138 | return false;
139 | }
140 | // wait some time needed to connection manager for waking up
141 | try {
142 | for (int counter = 0; counter < 30; counter++) {
143 | State checkState = connectivityManager.getNetworkInfo(
144 | ConnectivityManager.TYPE_MOBILE_HIPRI).getState();
145 | Log.d(Manager.TAG, "TYPE_MOBILE_HIPRI network state: "
146 | + checkState);
147 | if (0 == checkState.compareTo(State.CONNECTED))
148 | break;
149 | Thread.sleep(1000);
150 | }
151 | } catch (InterruptedException e) {
152 | // nothing to do
153 | }
154 | boolean resultBool = connectivityManager.requestRouteToHost(
155 | ConnectivityManager.TYPE_MOBILE_HIPRI, hostAddress);
156 | Log.d(Manager.TAG, "requestRouteToHost result: " + resultBool);
157 | if (!resultBool)
158 | Log.e(Manager.TAG,
159 | "Wrong requestRouteToHost result: expected true, but was false");
160 |
161 | return resultBool;
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/services/Boot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.services;
22 |
23 | import android.content.BroadcastReceiver;
24 | import android.content.Context;
25 | import android.content.Intent;
26 |
27 | public class Boot extends BroadcastReceiver {
28 | @Override
29 | public void onReceive(Context context, Intent intent) {
30 | if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
31 | context.startService(new Intent(context, MainService.class));
32 | }
33 | }
34 | }
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/services/MainService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.services;
22 |
23 | import android.app.Service;
24 | import android.content.Intent;
25 | import android.os.IBinder;
26 | import android.util.Log;
27 | import android.widget.Toast;
28 | import be.uclouvain.multipathcontrol.MPCtrl;
29 | import be.uclouvain.multipathcontrol.global.Manager;
30 |
31 | public class MainService extends Service {
32 |
33 | private MPCtrl mpctrl;
34 |
35 | @Override
36 | public IBinder onBind(Intent intent) {
37 | return null; // not allow binding
38 | }
39 |
40 | public void onCreate() {
41 | super.onCreate();
42 | mpctrl = Manager.create(getApplicationContext());
43 | Log.i(Manager.TAG, "Create service");
44 | if (mpctrl == null) {
45 | Toast.makeText(this,
46 | "MPControl: It seems this is not a rooted device",
47 | Toast.LENGTH_LONG).show();
48 | stopSelf();
49 | return;
50 | }
51 | }
52 |
53 | public void onDestroy() {
54 | super.onDestroy();
55 | if (mpctrl != null) {
56 | Manager.destroy(getApplicationContext());
57 | Log.i(Manager.TAG, "Destroy service");
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/GetIPTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import java.io.BufferedReader;
24 | import java.io.IOException;
25 | import java.io.InputStreamReader;
26 |
27 | import org.apache.http.HttpResponse;
28 | import org.apache.http.client.HttpClient;
29 | import org.apache.http.client.methods.HttpGet;
30 |
31 | import android.content.SharedPreferences.Editor;
32 | import android.os.AsyncTask;
33 | import android.util.Log;
34 | import be.uclouvain.multipathcontrol.global.Manager;
35 |
36 | public class GetIPTask extends AsyncTask {
37 |
38 | private final Editor editor;
39 |
40 | public GetIPTask(Editor editor) {
41 | super();
42 | this.editor = editor;
43 | }
44 |
45 | @Override
46 | protected String doInBackground(String... arg0) {
47 | HttpClient httpClient = HttpUtils.getHttpClient(1000);
48 | if (httpClient == null)
49 | return null;
50 |
51 | HttpGet httpGet = new HttpGet(HttpUtils.BASEURI + '/' + arg0[0]);
52 | BufferedReader bReader = null;
53 | String line = null;
54 | try {
55 | HttpResponse response = httpClient.execute(httpGet);
56 | bReader = new BufferedReader(new InputStreamReader(
57 | response.getEntity().getContent()));
58 | line = bReader.readLine();
59 | bReader.close();
60 | } catch (IOException e) {
61 | Log.e(Manager.TAG, "Error when getting ip: " + e.getMessage());
62 | } finally {
63 | try {
64 | if (bReader != null)
65 | bReader.close();
66 | } catch (IOException ex) {
67 | ex.printStackTrace();
68 | }
69 | }
70 | return line;
71 | }
72 |
73 | protected void onPostExecute(String ip) {
74 | if (ip != null && !ip.isEmpty()) {
75 | editor.putString(SaveDataHandover.PREFS_EXT_IP, ip);
76 | editor.commit();
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/HttpUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import org.apache.http.auth.AuthScope;
24 | import org.apache.http.auth.Credentials;
25 | import org.apache.http.auth.UsernamePasswordCredentials;
26 | import org.apache.http.client.CredentialsProvider;
27 | import org.apache.http.client.HttpClient;
28 | import org.apache.http.impl.client.DefaultHttpClient;
29 | import org.apache.http.params.BasicHttpParams;
30 | import org.apache.http.params.HttpConnectionParams;
31 | import org.apache.http.params.HttpParams;
32 |
33 | import be.uclouvain.multipathcontrol.global.ConfigServer;
34 |
35 | public class HttpUtils {
36 |
37 | public static final String BASEURI = "http://" + ConfigServer.hostname
38 | + ":" + ConfigServer.port;
39 |
40 | private HttpUtils() {
41 | }
42 |
43 | public static HttpClient getHttpClient(int timeout) {
44 | if (ConfigServer.hostname.isEmpty())
45 | return null;
46 |
47 | DefaultHttpClient defaultHttpClient;
48 | if (timeout > 0)
49 | defaultHttpClient = new DefaultHttpClient(getParamTimeout(timeout));
50 | else
51 | defaultHttpClient = new DefaultHttpClient();
52 | if (ConfigServer.username != null && !ConfigServer.username.isEmpty()) {
53 | Credentials creds = new UsernamePasswordCredentials(
54 | ConfigServer.username, ConfigServer.password);
55 | AuthScope scope = new AuthScope(ConfigServer.hostname,
56 | ConfigServer.port);
57 | CredentialsProvider credProvider = defaultHttpClient
58 | .getCredentialsProvider();
59 | credProvider.setCredentials(scope, creds);
60 | }
61 | return defaultHttpClient;
62 | }
63 |
64 | public static HttpClient getHttpClient() {
65 | return getHttpClient(0);
66 | }
67 |
68 | /**
69 | * @param timeout in ms
70 | * @return BasicHttpParams with timeout for the connection and the socket
71 | */
72 | private static HttpParams getParamTimeout(int timeout) {
73 | HttpParams httpParameters = new BasicHttpParams();
74 | HttpConnectionParams.setConnectionTimeout(httpParameters, timeout);
75 | HttpConnectionParams.setSoTimeout(httpParameters, timeout);
76 | return httpParameters;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/JSONSender.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import java.io.File;
24 | import java.io.IOException;
25 | import java.util.Locale;
26 | import java.util.Map;
27 | import java.util.Set;
28 |
29 | import org.apache.http.HttpResponse;
30 | import org.apache.http.HttpStatus;
31 | import org.apache.http.client.HttpClient;
32 | import org.apache.http.client.methods.HttpPost;
33 | import org.apache.http.entity.StringEntity;
34 | import org.json.JSONObject;
35 |
36 | import android.content.Context;
37 | import android.content.SharedPreferences;
38 | import android.util.Log;
39 | import be.uclouvain.multipathcontrol.global.Config;
40 | import be.uclouvain.multipathcontrol.global.ConfigServer;
41 | import be.uclouvain.multipathcontrol.global.Manager;
42 |
43 | public class JSONSender {
44 |
45 | private JSONObject jsonObject;
46 | private SharedPreferences prefs;
47 | private StatsCategories category;
48 | private String name;
49 | private String xmlFilePath;
50 |
51 | private static boolean isSending = false;
52 |
53 | public JSONSender(Context context, String name, StatsCategories category) {
54 | this.category = category;
55 | this.name = name;
56 | this.prefs = context.getSharedPreferences(name, Context.MODE_PRIVATE);
57 | this.xmlFilePath = context.getFilesDir().getParent() + File.separator
58 | + "shared_prefs" + File.separator + name + ".xml";
59 |
60 | Map map = prefs.getAll();
61 | if (map == null || !map.containsKey(SaveDataAbstract.PREFS_TIMESTAMP))
62 | this.jsonObject = null;
63 | else
64 | this.jsonObject = new JSONObject(map);
65 | }
66 |
67 | public JSONSender(JSONObject jsonObject, StatsCategories category) {
68 | this.jsonObject = jsonObject;
69 | this.category = category;
70 | this.prefs = null;
71 | }
72 |
73 | // avoid uploading multiple time
74 | private static boolean trySending() {
75 | synchronized (JSONSender.class) {
76 | if (isSending || ConfigServer.hostname.isEmpty())
77 | return false;
78 | isSending = true;
79 | return true;
80 | }
81 | }
82 |
83 | public static void stopSending() {
84 | synchronized (JSONSender.class) {
85 | isSending = false;
86 | }
87 | }
88 |
89 | /**
90 | * Get all sets of data that have to be send, prepare the JSON and send it.
91 | * If correctly sent, clear data from settings.
92 | */
93 | public static void sendAll(Context context) {
94 | if (!trySending())
95 | return;
96 |
97 | SharedPreferences settings = context.getSharedPreferences(
98 | Config.PREFS_NAME, Context.MODE_PRIVATE);
99 |
100 | for (StatsCategories category : StatsCategories.values()) {
101 | String key = Config.PREFS_STATS_SET + '_' + category;
102 | Set statsSet = settings.getStringSet(key, null);
103 | if (statsSet == null)
104 | continue;
105 |
106 | JSONSender jsonSenders[] = new JSONSender[statsSet.size()];
107 | int i = 0;
108 | // Get all data sets and send them
109 | for (String name : statsSet)
110 | jsonSenders[i++] = new JSONSender(context, name, category);
111 |
112 | JSONSenderTask jsonSenderTask = new JSONSenderTask(settings,
113 | category);
114 | jsonSenderTask.execute(jsonSenders);
115 | }
116 | }
117 |
118 | /**
119 | * Send a POST request to the server (using ConfigServer class) with the
120 | * JSON string from jsonObject
121 | *
122 | * @return true if the server return status code 200
123 | */
124 | public boolean send(HttpClient httpClient) {
125 | if (jsonObject == null || ConfigServer.hostname.isEmpty())
126 | return false;
127 | HttpPost httpPost = new HttpPost(HttpUtils.BASEURI + "/"
128 | + category.name().toLowerCase(Locale.ENGLISH));
129 | String jsonString = jsonObject.toString();
130 | try {
131 | httpPost.setEntity(new StringEntity(jsonString));
132 | httpPost.setHeader("Accept", "application/json");
133 | httpPost.setHeader("Content-type", "application/json");
134 | HttpResponse response = httpClient.execute(httpPost);
135 | int rc = response.getStatusLine().getStatusCode();
136 | Log.d(Manager.TAG, "Get answer: " + rc);
137 | response.getEntity().consumeContent();
138 | return rc == HttpStatus.SC_OK;
139 | } catch (IOException e) {
140 | Log.e(Manager.TAG,
141 | "Error when sending [" + jsonString + "]: "
142 | + e.getMessage());
143 | }
144 | return false;
145 | }
146 |
147 | public void clear() {
148 | if (prefs != null) {
149 | prefs.edit().clear().commit();
150 | new File(xmlFilePath).delete(); // not needed to keep empty xml file
151 | }
152 | }
153 |
154 | public JSONObject getJSONObject() {
155 | return jsonObject;
156 | }
157 |
158 | public StatsCategories getCategory() {
159 | return category;
160 | }
161 |
162 | public String getName() {
163 | return name;
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/JSONSenderTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import java.util.ArrayList;
24 | import java.util.Collection;
25 |
26 | import org.apache.http.client.HttpClient;
27 |
28 | import android.content.SharedPreferences;
29 | import android.os.AsyncTask;
30 | import android.util.Log;
31 | import be.uclouvain.multipathcontrol.global.Manager;
32 |
33 | public class JSONSenderTask extends
34 | AsyncTask> {
35 |
36 | private SharedPreferences settings;
37 | private StatsCategories category;
38 | private HttpClient httpClient;
39 |
40 | public JSONSenderTask(SharedPreferences settings, StatsCategories category) {
41 | super();
42 | this.settings = settings;
43 | this.category = category;
44 | this.httpClient = HttpUtils.getHttpClient();
45 | }
46 |
47 | @Override
48 | protected Collection doInBackground(JSONSender... jsonSenders) {
49 | // list of name of prefs that have to be removed
50 | if (httpClient == null)
51 | return null;
52 |
53 | Collection collection = new ArrayList(
54 | jsonSenders.length);
55 | for (JSONSender jsonSender : jsonSenders) {
56 | Log.d(Manager.TAG, "Try sending: " + jsonSender.getName() + " - "
57 | + jsonSender.getCategory());
58 |
59 | // remove it also is we had problem when creating JSONSender object
60 | if (jsonSender.getJSONObject() == null
61 | || jsonSender.send(httpClient)) {
62 | Log.d(Manager.TAG, "To be cleared: " + jsonSender.getName());
63 | collection.add(jsonSender.getName());
64 | jsonSender.clear();
65 | } else {
66 | Log.w(Manager.TAG, "Not able to send: " + jsonSender.getName());
67 | }
68 | }
69 | return collection;
70 | }
71 |
72 | protected void onPostExecute(Collection collection) {
73 | if (collection != null)
74 | SaveDataAbstract.removeFromPrefs(settings, collection, category);
75 | JSONSender.stopSending();
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/LocationState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import android.content.Context;
24 | import android.location.Location;
25 | import android.os.Bundle;
26 | import android.util.Log;
27 | import be.uclouvain.multipathcontrol.global.Manager;
28 |
29 | import com.google.android.gms.common.ConnectionResult;
30 | import com.google.android.gms.common.GooglePlayServicesUtil;
31 | import com.google.android.gms.common.api.GoogleApiClient;
32 | import com.google.android.gms.common.api.GoogleApiClient.ConnectionCallbacks;
33 | import com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener;
34 | import com.google.android.gms.location.LocationListener;
35 | import com.google.android.gms.location.LocationRequest;
36 | import com.google.android.gms.location.LocationServices;
37 |
38 | public class LocationState {
39 |
40 | private final GoogleApiClient googleApiClient;
41 | private final Context context;
42 | private int priority;
43 |
44 | private static LocationState instance = null;
45 |
46 | public static LocationState getInstance(Context context, int priority) {
47 | if (instance == null)
48 | instance = new LocationState(context, priority);
49 | return instance;
50 | }
51 |
52 | public static LocationState getInstance(Context context) {
53 | return getInstance(context, LocationRequest.PRIORITY_LOW_POWER);
54 | }
55 |
56 | public static LocationState getInstance(Context context,
57 | boolean savePowerGPS) {
58 | return getInstance(context, getPriority(savePowerGPS));
59 | }
60 |
61 | private LocationState(Context context, int priority) {
62 | this.context = context;
63 | this.priority = priority;
64 | googleApiClient = new GoogleApiClient.Builder(context)
65 | .addConnectionCallbacks(googleApiLocationConnectionCallbacks)
66 | .addOnConnectionFailedListener(
67 | googleApiLocationCConnectionFailedListener)
68 | .addApi(LocationServices.API).build();
69 | googleApiClient.connect();
70 | }
71 |
72 | public Location getLastLocation() {
73 | if (isGPSAvailable() && googleApiClient.isConnected())
74 | return LocationServices.FusedLocationApi
75 | .getLastLocation(googleApiClient);
76 | return null;
77 | }
78 |
79 | public static int getPriority(boolean savePowerGPS) {
80 | return savePowerGPS ? LocationRequest.PRIORITY_LOW_POWER
81 | : LocationRequest.PRIORITY_HIGH_ACCURACY;
82 | }
83 |
84 | public int getPriority() {
85 | return priority;
86 | }
87 |
88 | /**
89 | * @param priority see {@link LocationRequest}
90 | */
91 | public void setPriority(int priority) {
92 | if (this.priority == priority)
93 | return;
94 | this.priority = priority;
95 |
96 | // no need to change priority when not assigned
97 | if (!googleApiClient.isConnected())
98 | return;
99 |
100 | registerLocationListener();
101 | }
102 |
103 | public void setPriority(boolean savePowerGPS) {
104 | setPriority(getPriority(savePowerGPS));
105 | }
106 |
107 | /**
108 | * RequestLocationUpdates depending of the priority.
109 | *
110 | * @pre googleApiClient has to be connected
111 | */
112 | private synchronized void registerLocationListener() {
113 | if (!isGPSAvailable())
114 | return;
115 |
116 | // seems we can remove it even if it not exists
117 | LocationServices.FusedLocationApi.removeLocationUpdates(
118 | googleApiClient, locationListener);
119 |
120 | LocationRequest request = new LocationRequest();
121 | request.setPriority(priority);
122 | Log.d(Manager.TAG, "New priority: " + priority);
123 | // we need update
124 | if (priority == LocationRequest.PRIORITY_HIGH_ACCURACY)
125 | request.setInterval(1000).setFastestInterval(1000);
126 |
127 | LocationServices.FusedLocationApi.requestLocationUpdates(
128 | googleApiClient, request, locationListener);
129 | }
130 |
131 | private boolean isGPSAvailable() {
132 | int returnCode = GooglePlayServicesUtil
133 | .isGooglePlayServicesAvailable(context);
134 | if (returnCode != ConnectionResult.SUCCESS) {
135 | Log.e(Manager.TAG,
136 | GooglePlayServicesUtil.getErrorString(returnCode));
137 | return false;
138 | }
139 | return true;
140 | }
141 |
142 | private ConnectionCallbacks googleApiLocationConnectionCallbacks = new ConnectionCallbacks() {
143 |
144 | @Override
145 | public void onConnectionSuspended(int i) {
146 | Log.w(Manager.TAG, "GooglePlayService connection suspended: " + i);
147 | googleApiClient.connect();
148 | }
149 |
150 | @Override
151 | public void onConnected(Bundle arg0) {
152 | Log.d(Manager.TAG, "GooglePlayService connected");
153 | registerLocationListener();
154 | }
155 | };
156 | private OnConnectionFailedListener googleApiLocationCConnectionFailedListener = new OnConnectionFailedListener() {
157 |
158 | @Override
159 | public void onConnectionFailed(ConnectionResult r) {
160 | Log.w(Manager.TAG, "GooglePlayService connection failed: " + r);
161 | }
162 | };
163 |
164 | private LocationListener locationListener = new LocationListener() {
165 | @Override
166 | public void onLocationChanged(Location arg0) {
167 | // do nothing, we will use getLastLocation()...
168 | Log.d(Manager.TAG, "New location: " + arg0);
169 | }
170 | };
171 | }
172 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/PhoneState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import java.lang.reflect.Method;
24 |
25 | import android.telephony.PhoneStateListener;
26 | import android.telephony.ServiceState;
27 | import android.telephony.SignalStrength;
28 | import android.telephony.TelephonyManager;
29 |
30 | public class PhoneState {
31 |
32 | private static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
33 |
34 | private static final int SIGNAL_STRENGTH_POOR = 1;
35 | private static final int SIGNAL_STRENGTH_MODERATE = 2;
36 | private static final int SIGNAL_STRENGTH_GOOD = 3;
37 | private static final int SIGNAL_STRENGTH_GREAT = 4;
38 |
39 | private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
40 | private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
41 | private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8; // = good?
42 |
43 | private TelephonyManager telephonyManager;
44 |
45 | private int lastSignalStrength;
46 | private int lastSignalStrengthDbm;
47 | private int lastBer;
48 |
49 | private static PhoneState instance = null;
50 |
51 | public static PhoneState getInstance(TelephonyManager telephonyManager) {
52 | if (instance == null)
53 | instance = new PhoneState(telephonyManager);
54 | return instance;
55 | }
56 |
57 | private PhoneState(TelephonyManager telephonyManager) {
58 | this.telephonyManager = telephonyManager;
59 | telephonyManager.listen(phoneStateListener,
60 | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
61 | | PhoneStateListener.LISTEN_SERVICE_STATE);
62 | }
63 |
64 | public int getLastSignalStrength() {
65 | return lastSignalStrength;
66 | }
67 |
68 | public int getLastSignalStrengthDbm() {
69 | return lastSignalStrengthDbm;
70 | }
71 |
72 | public int getLastBer() {
73 | return lastBer;
74 | }
75 |
76 | // src: http://stackoverflow.com/a/19965362
77 | public String getNetworkType() {
78 | int networkType = telephonyManager.getNetworkType();
79 | switch (networkType) {
80 | case TelephonyManager.NETWORK_TYPE_1xRTT:
81 | return "1xRTT";
82 | case TelephonyManager.NETWORK_TYPE_CDMA:
83 | return "CDMA";
84 | case TelephonyManager.NETWORK_TYPE_EDGE:
85 | return "EDGE";
86 | case TelephonyManager.NETWORK_TYPE_EHRPD:
87 | return "eHRPD";
88 | case TelephonyManager.NETWORK_TYPE_EVDO_0:
89 | return "EVDO rev. 0";
90 | case TelephonyManager.NETWORK_TYPE_EVDO_A:
91 | return "EVDO rev. A";
92 | case TelephonyManager.NETWORK_TYPE_EVDO_B:
93 | return "EVDO rev. B";
94 | case TelephonyManager.NETWORK_TYPE_GPRS:
95 | return "GPRS";
96 | case TelephonyManager.NETWORK_TYPE_HSDPA:
97 | return "HSDPA";
98 | case TelephonyManager.NETWORK_TYPE_HSPA:
99 | return "HSPA";
100 | case TelephonyManager.NETWORK_TYPE_HSPAP:
101 | return "HSPA+";
102 | case TelephonyManager.NETWORK_TYPE_HSUPA:
103 | return "HSUPA";
104 | case TelephonyManager.NETWORK_TYPE_IDEN:
105 | return "iDen";
106 | case TelephonyManager.NETWORK_TYPE_LTE:
107 | return "LTE";
108 | case TelephonyManager.NETWORK_TYPE_UMTS:
109 | return "UMTS";
110 | case TelephonyManager.NETWORK_TYPE_UNKNOWN:
111 | return "Unknown";
112 | }
113 | return "Error";
114 | }
115 |
116 | public String getSimState() {
117 | int simState = telephonyManager.getSimState();
118 | switch (simState) {
119 | case TelephonyManager.SIM_STATE_ABSENT:
120 | return "Absent";
121 | case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
122 | return "NetworkLocked";
123 | case TelephonyManager.SIM_STATE_PIN_REQUIRED:
124 | return "PinRequired";
125 | case TelephonyManager.SIM_STATE_PUK_REQUIRED:
126 | return "PukRequired";
127 | case TelephonyManager.SIM_STATE_READY:
128 | return "Ready";
129 | case TelephonyManager.SIM_STATE_UNKNOWN:
130 | return "Unknown";
131 | }
132 | return "Error";
133 | }
134 |
135 | public String getDataState() {
136 | int dataState = telephonyManager.getDataState();
137 | switch (dataState) {
138 | case TelephonyManager.DATA_CONNECTED:
139 | return "Connected";
140 | case TelephonyManager.DATA_CONNECTING:
141 | return "Connecting";
142 | case TelephonyManager.DATA_DISCONNECTED:
143 | return "Disconnected";
144 | case TelephonyManager.DATA_SUSPENDED:
145 | return "Suspended";
146 | }
147 | return "Error";
148 | }
149 |
150 | public String getDataActivity() {
151 | int dataActivity = telephonyManager.getDataActivity();
152 | switch (dataActivity) {
153 | case TelephonyManager.DATA_ACTIVITY_DORMANT:
154 | return "Dormant";
155 | case TelephonyManager.DATA_ACTIVITY_IN:
156 | return "In";
157 | case TelephonyManager.DATA_ACTIVITY_INOUT:
158 | return "InOut";
159 | case TelephonyManager.DATA_ACTIVITY_NONE:
160 | return "None";
161 | case TelephonyManager.DATA_ACTIVITY_OUT:
162 | return "Out";
163 | }
164 | return "Error";
165 | }
166 |
167 | /**
168 | * @return a value between 0 {@link #SIGNAL_STRENGTH_NONE_OR_UNKNOWN} and 4
169 | * {@link #SIGNAL_STRENGTH_GREAT}.
170 | */
171 | private static int getLevel(SignalStrength signalStrength) {
172 | if (signalStrength.isGsm())
173 | return getGSMSignalStrength(signalStrength);
174 | return 0;
175 | }
176 |
177 | /**
178 | * @return the signal strength as dBm.
179 | */
180 | private static int getDbm(TelephonyManager telephonyManager,
181 | SignalStrength signalStrength) {
182 | if (!signalStrength.isGsm())
183 | return 0;
184 |
185 | if (getLteLevel(telephonyManager, signalStrength) == SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
186 | return getGsmDbm(signalStrength);
187 | else
188 | return getLteDbm(signalStrength);
189 | }
190 |
191 | /**
192 | * Get signal level as an int from 0..4
193 | */
194 | private static int getGSMSignalStrength(SignalStrength signalStrength) {
195 | // ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
196 | // asu = 0 (-113dB or less) is very weak
197 | // signal, its better to show 0 bars to the user in such cases.
198 | // asu = 99 is a special case, where the signal strength is unknown.
199 | int asu = signalStrength.getGsmSignalStrength();
200 | if (asu <= 2 || asu == 99)
201 | return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
202 | else if (asu >= GSM_SIGNAL_STRENGTH_GREAT)
203 | return SIGNAL_STRENGTH_GREAT;
204 | else if (asu >= GSM_SIGNAL_STRENGTH_GOOD)
205 | return SIGNAL_STRENGTH_GOOD;
206 | else if (asu >= GSM_SIGNAL_STRENGTH_MODERATE)
207 | return SIGNAL_STRENGTH_MODERATE;
208 | else
209 | return SIGNAL_STRENGTH_POOR;
210 | }
211 |
212 | /**
213 | * Get the GSM signal strength as dBm
214 | */
215 | private static int getGsmDbm(SignalStrength signalStrength) {
216 | int dBm;
217 |
218 | int level = signalStrength.getGsmSignalStrength();
219 | int asu = level == 99 ? SIGNAL_STRENGTH_NONE_OR_UNKNOWN : level;
220 | if (asu != SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
221 | dBm = -113 + 2 * asu;
222 | } else {
223 | dBm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
224 | }
225 | return dBm;
226 | }
227 |
228 | /**
229 | * Get LTE as level 0..4
230 | */
231 | private static int getLteLevel(TelephonyManager telephonyManager,
232 | SignalStrength signalStrength) {
233 | // For now there's no other way besides reflection :( The getLteLevel()
234 | // method
235 | // in the SignalStrength class access private fields.
236 | // On some Samsung devices, getLteLevel() can actually return 4 (the
237 | // highest signal strength) even if we're not on Lte.
238 | // It seems that Samsung has reimplemented getLteLevel(). So we add an
239 | // extra check to make sure we only use Lte level if we're on LTE.
240 |
241 | if (telephonyManager.getNetworkType() != TelephonyManager.NETWORK_TYPE_LTE) {
242 | return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
243 | }
244 | try {
245 | Method methodGetLteLevel = SignalStrength.class
246 | .getMethod("getLteLevel");
247 | return (Integer) methodGetLteLevel.invoke(signalStrength);
248 | } catch (Throwable t) {
249 | return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
250 | }
251 | }
252 |
253 | /**
254 | * Get LTE as dBm
255 | */
256 | private static int getLteDbm(SignalStrength signalStrength) {
257 | // For now there's no other way besides reflection :( The getLteDbm()
258 | // method
259 | // in the SignalStrength class returns a private field which is not
260 | // accessible in any public, non-hidden methods.
261 | try {
262 | Method methodGetLteDbm = SignalStrength.class
263 | .getMethod("getLteDbm");
264 | return (Integer) methodGetLteDbm.invoke(signalStrength);
265 | } catch (Throwable t) {
266 | return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
267 | }
268 | }
269 |
270 | private final PhoneStateListener phoneStateListener = new PhoneStateListener() {
271 | @Override
272 | public void onSignalStrengthsChanged(SignalStrength signalStrength) {
273 | lastSignalStrength = getLevel(signalStrength);
274 | lastSignalStrengthDbm = getDbm(telephonyManager, signalStrength);
275 | lastBer = signalStrength.getGsmBitErrorRate();
276 | }
277 |
278 | @Override
279 | public void onServiceStateChanged(ServiceState serviceState) {
280 | if (serviceState.getState() != ServiceState.STATE_IN_SERVICE) {
281 | lastSignalStrength = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
282 | lastSignalStrengthDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
283 | lastBer = 0;
284 | }
285 | }
286 | };
287 | }
288 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/SaveDataAbstract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import java.util.Collection;
24 | import java.util.Date;
25 | import java.util.HashSet;
26 | import java.util.Set;
27 | import java.util.concurrent.locks.Lock;
28 | import java.util.concurrent.locks.ReentrantLock;
29 |
30 | import android.content.Context;
31 | import android.content.SharedPreferences;
32 | import android.content.SharedPreferences.Editor;
33 | import android.net.wifi.WifiInfo;
34 | import android.net.wifi.WifiManager;
35 | import be.uclouvain.multipathcontrol.global.Config;
36 |
37 | /**
38 | * The goal of this abstract class is to define a new environment to save data.
39 | *
40 | * Simply extends this class and put new data via the editor.
41 | *
42 | * The name of the new prefs will be stored in Config.PREFS_STATS_SET_category
43 | */
44 | public abstract class SaveDataAbstract {
45 | public static final String PREFS_TIMESTAMP = "timestamp";
46 | public static final String PREFS_WIFI_MAC = "wifiMac";
47 |
48 | private static String wifiMac = null;
49 | private static final Lock mutex = new ReentrantLock(true);
50 |
51 | protected Editor editor;
52 | private String key;
53 | private long timestamp;
54 |
55 | public SaveDataAbstract(Context context, StatsCategories category) {
56 | this.timestamp = new Date().getTime();
57 |
58 | String sharedPrefName = Long.toString(timestamp);
59 | this.editor = context.getSharedPreferences(sharedPrefName,
60 | Context.MODE_PRIVATE).edit();
61 | editor.putLong(PREFS_TIMESTAMP, timestamp);
62 | editor.putString(PREFS_WIFI_MAC, getWiFiMac(context));
63 |
64 | SharedPreferences settings = context.getSharedPreferences(
65 | Config.PREFS_NAME, Context.MODE_PRIVATE);
66 | addPrefToList(settings, sharedPrefName, category);
67 | }
68 |
69 | private static String getWiFiMac(Context context) {
70 | if (wifiMac != null)
71 | return wifiMac;
72 | WifiManager wifiMan = (WifiManager) context
73 | .getSystemService(Context.WIFI_SERVICE);
74 | WifiInfo wifiInf = wifiMan.getConnectionInfo();
75 | wifiMac = wifiInf.getMacAddress();
76 | return wifiMac;
77 | }
78 |
79 | private void addPrefToList(SharedPreferences settings,
80 | String sharedPrefName, StatsCategories category) {
81 | key = Config.PREFS_STATS_SET + '_' + category;
82 |
83 | mutex.lock();
84 |
85 | Set statsSet = settings.getStringSet(key, null);
86 | if (statsSet == null)
87 | statsSet = new HashSet(1);
88 | else
89 | // We need a copy: see doc about SharedPreferences.getStringSet()
90 | statsSet = new HashSet(statsSet);
91 |
92 | statsSet.add(sharedPrefName);
93 | settings.edit().putStringSet(key, statsSet).commit();
94 |
95 | mutex.unlock();
96 | }
97 |
98 | public static void removeFromPrefs(SharedPreferences settings,
99 | Collection sharedPrefNames, StatsCategories category) {
100 | String key = Config.PREFS_STATS_SET + '_' + category;
101 |
102 | mutex.lock();
103 |
104 | Set statsSet = settings.getStringSet(key, null);
105 | if (statsSet != null) { // should not be null...
106 | statsSet = new HashSet(statsSet);
107 | statsSet.removeAll(sharedPrefNames);
108 | settings.edit().putStringSet(key, statsSet).commit();
109 | }
110 |
111 | mutex.unlock();
112 | }
113 |
114 | public String getKey() {
115 | return key;
116 | }
117 |
118 | public long getTimestamp() {
119 | return timestamp;
120 | }
121 |
122 | protected void save() {
123 | editor.commit();
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/SaveDataApp.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | import android.content.Context;
24 | import android.content.pm.PackageInfo;
25 | import android.content.pm.PackageManager.NameNotFoundException;
26 | import be.uclouvain.multipathcontrol.global.Config;
27 |
28 | public class SaveDataApp extends SaveDataAbstract {
29 |
30 | public static final String PREFS_VERSION_NAME = "versionName";
31 | public static final String PREFS_VERSION_CODE = "versionCode";
32 | public static final String PREFS_LAST_UPDATE = "lastUpdate";
33 | public static final String PREFS_STATUS = "enable";
34 | public static final String PREFS_DEFAULT_DATA = "defRouteCell";
35 | public static final String PREFS_DATA_BACKUP = "cellBackup";
36 | public static final String PREFS_SAVE_BATTERY = "saveBattery";
37 | public static final String PREFS_SAVE_POW_GPS = "savePowerGPS";
38 | public static final String PREFS_IPV6 = "ipv6";
39 | public static final String PREFS_TRACKING = "tracking";
40 | public static final String PREFS_TCPCC = "TCPCCAlgo";
41 |
42 | private static PackageInfo info = null;
43 |
44 | public SaveDataApp(Context context) {
45 | super(context, StatsCategories.STARTUP);
46 |
47 | setVersion(context);
48 | setPref();
49 |
50 | save();
51 | }
52 |
53 | private static synchronized PackageInfo getInfo(Context context) {
54 | if (info == null) {
55 | try {
56 | info = context.getPackageManager().getPackageInfo(
57 | context.getPackageName(), 0);
58 | } catch (NameNotFoundException e) {
59 | // should not happen... our package
60 | e.printStackTrace();
61 | return null;
62 | }
63 | }
64 | return info;
65 | }
66 |
67 | private void setVersion(Context context) {
68 | if (getInfo(context) == null)
69 | return;
70 |
71 | editor.putString(PREFS_VERSION_NAME, info.versionName);
72 | editor.putInt(PREFS_VERSION_CODE, info.versionCode);
73 | editor.putLong(PREFS_LAST_UPDATE, info.lastUpdateTime);
74 | }
75 |
76 | private void setPref() {
77 | editor.putBoolean(PREFS_STATUS, Config.mEnabled);
78 | editor.putBoolean(PREFS_DEFAULT_DATA, Config.defaultRouteData);
79 | editor.putBoolean(PREFS_DATA_BACKUP, Config.dataBackup);
80 | editor.putBoolean(PREFS_SAVE_BATTERY, Config.saveBattery);
81 | editor.putBoolean(PREFS_IPV6, Config.ipv6);
82 | editor.putBoolean(PREFS_SAVE_POW_GPS, Config.savePowerGPS);
83 | editor.putBoolean(PREFS_TRACKING, Config.tracking);
84 | editor.putString(PREFS_TCPCC, Config.tcpcc);
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/SaveDataHandover.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | *
20 | * Thanks to Carmen Alvarez for his Network-Monitor project!
21 | * https://github.com/caarmen/network-monitor/
22 | */
23 |
24 | package be.uclouvain.multipathcontrol.stats;
25 |
26 | import java.io.BufferedReader;
27 | import java.io.FileReader;
28 | import java.io.IOException;
29 | import java.net.Inet4Address;
30 | import java.net.InetAddress;
31 | import java.net.NetworkInterface;
32 | import java.util.Enumeration;
33 | import java.util.List;
34 |
35 | import android.content.Context;
36 | import android.location.Location;
37 | import android.net.ConnectivityManager;
38 | import android.net.NetworkInfo;
39 | import android.net.wifi.ScanResult;
40 | import android.net.wifi.WifiInfo;
41 | import android.net.wifi.WifiManager;
42 | import android.provider.Settings;
43 | import android.provider.Settings.SettingNotFoundException;
44 | import android.telephony.CellLocation;
45 | import android.telephony.TelephonyManager;
46 | import android.telephony.gsm.GsmCellLocation;
47 | import android.util.Log;
48 | import be.uclouvain.multipathcontrol.global.Config;
49 | import be.uclouvain.multipathcontrol.global.Manager;
50 | import be.uclouvain.multipathcontrol.system.Cmd;
51 | import be.uclouvain.multipathcontrol.system.IPRouteUtils;
52 |
53 | public class SaveDataHandover extends SaveDataAbstract {
54 |
55 | public static final String PREFS_AIRPLANE = "airplane";
56 | public static final String PREFS_CELL_BER = "cellBer";
57 | public static final String PREFS_CELL_SIGNAL_4 = "cellSignal4";
58 | public static final String PREFS_CELL_SIGNAL_DBM = "cellSignaldBm";
59 | public static final String PREFS_DATA_ACTIVITY = "dataActivity";
60 | public static final String PREFS_DATA_STATE = "dataState";
61 | public static final String PREFS_CELL_TYPE = "cellType";
62 | public static final String PREFS_EXT_IP = "extIp";
63 | public static final String PREFS_GSM_CELL_LAC = "gsmCellLac";
64 | public static final String PREFS_GSM_FULL_CELL_ID = "gsmFullCellId";
65 | public static final String PREFS_GSM_RNC = "gsmRNC";
66 | public static final String PREFS_GSM_SHORT_CELL_ID = "gsmShortCellId";
67 | public static final String PREFS_IFACES = "ifaces";
68 | public static final String PREFS_IP_WIFI_V4 = "ipWifi4";
69 | public static final String PREFS_IP_WIFI_V6 = "ipWifi6";
70 | public static final String PREFS_IP_RMNET_V4 = "ipRMNet4";
71 | public static final String PREFS_IP_RMNET_V6 = "ipRMNet6";
72 | public static final String PREFS_NETSTAT = "netstat";
73 | public static final String PREFS_NETWORK_AVAILABLE = "netAvailable";
74 | public static final String PREFS_NETWORK_CONNECTED = "netConnected";
75 | public static final String PREFS_NETWORK_DSTATE = "netDState";
76 | public static final String PREFS_NETWORK_EXTRAS = "netExtras";
77 | public static final String PREFS_NETWORK_FAILOVER = "netFailover";
78 | public static final String PREFS_NETWORK_REASON = "netReason";
79 | public static final String PREFS_NETWORK_ROAMING = "netRoaming";
80 | public static final String PREFS_NETWORK_TYPE = "netType";
81 | public static final String PREFS_POS_ACCURACY = "posAccuracy";
82 | public static final String PREFS_POS_LATITUDE = "posLatitude";
83 | public static final String PREFS_POS_LONGITUDE = "posLongitude";
84 | public static final String PREFS_POS_SPEED = "posSpeed";
85 | public static final String PREFS_PROC_MPTCP = "procMPTCP";
86 | public static final String PREFS_PROC_MPTCP_FM = "procMPTCPFM";
87 | public static final String PREFS_SIM_OPERATOR = "simOperator";
88 | public static final String PREFS_SIM_STATE = "simState";
89 | public static final String PREFS_TRACKING = "tracking";
90 | public static final String PREFS_WIFI_BSSID = "wifiBSSID";
91 | public static final String PREFS_WIFI_FREQ = "wifiFreq";
92 | public static final String PREFS_WIFI_SIGNAL_4 = "wifiSignal4";
93 | public static final String PREFS_WIFI_SIGNAL_RSSI = "wifiSignalRSSI";
94 | public static final String PREFS_WIFI_SPEED = "wifiSpeed";
95 | public static final String PREFS_WIFI_SSID = "wifiSSID";
96 | public static final String PREFS_WIFI_STATE = "wifiState";
97 |
98 | private static ConnectivityManager connectivityManager = null;
99 | private static TelephonyManager telephonyManager = null;
100 | private static WifiManager wifiManager = null;
101 |
102 | private static PhoneState phoneState = null;
103 | private static LocationState locationState = null;
104 |
105 | private static synchronized void getStaticVarsSync(Context context) {
106 | if (connectivityManager == null)
107 | connectivityManager = (ConnectivityManager) context
108 | .getSystemService(Context.CONNECTIVITY_SERVICE);
109 | if (telephonyManager == null)
110 | telephonyManager = (TelephonyManager) context
111 | .getSystemService(Context.TELEPHONY_SERVICE);
112 | if (wifiManager == null)
113 | wifiManager = (WifiManager) context
114 | .getSystemService(Context.WIFI_SERVICE);
115 |
116 | if (phoneState == null)
117 | phoneState = PhoneState.getInstance(telephonyManager);
118 | if (locationState == null)
119 | locationState = LocationState.getInstance(context,
120 | Config.savePowerGPS);
121 | }
122 |
123 | private final boolean trackingSec;
124 |
125 | public SaveDataHandover(Context context, boolean trackingSec) {
126 | super(context, StatsCategories.HANDOVER);
127 |
128 | this.trackingSec = trackingSec;
129 | editor.putBoolean(PREFS_TRACKING, trackingSec);
130 |
131 | getStaticVarsSync(context);
132 |
133 | fromNetAsync();
134 |
135 | fromConnectivityManager(context);
136 | fromTelephonyManager(context);
137 | fromWifiManager(context);
138 |
139 | fromPhoneState();
140 | fromLocationState();
141 |
142 | fromNetworkInterface();
143 | fromSystem();
144 |
145 | fromSettings(context);
146 |
147 | save();
148 | }
149 |
150 | public SaveDataHandover(Context context) {
151 | this(context, false);
152 | }
153 |
154 | public static void savePowerGPS(boolean savePowerGPS) {
155 | if (locationState != null)
156 | locationState.setPriority(savePowerGPS);
157 | }
158 |
159 | // Src: https://github.com/caarmen/network-monitor/blob/master/networkmonitor/src/main/java/ca/rmen/android/networkmonitor/app/service/datasources/ActiveNetworkInfoDataSource.java
160 | private void fromConnectivityManager(Context context) {
161 | NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
162 | if (activeNetworkInfo == null)
163 | return;
164 |
165 | String networkType = activeNetworkInfo.getTypeName();
166 | String networkSubType = activeNetworkInfo.getSubtypeName();
167 | if (networkSubType != null && !networkSubType.isEmpty())
168 | networkType += "/" + networkSubType;
169 |
170 | editor.putString(PREFS_NETWORK_TYPE, networkType);
171 | editor.putBoolean(PREFS_NETWORK_ROAMING, activeNetworkInfo.isRoaming());
172 | editor.putBoolean(PREFS_NETWORK_AVAILABLE, activeNetworkInfo.isAvailable());
173 | editor.putBoolean(PREFS_NETWORK_CONNECTED, activeNetworkInfo.isConnected());
174 | editor.putBoolean(PREFS_NETWORK_FAILOVER, activeNetworkInfo.isFailover());
175 | editor.putString(PREFS_NETWORK_DSTATE, activeNetworkInfo.getDetailedState().toString());
176 | String reason = activeNetworkInfo.getReason();
177 | if (reason != null && !reason.isEmpty())
178 | editor.putString(PREFS_NETWORK_REASON, reason);
179 | editor.putString(PREFS_NETWORK_EXTRAS, activeNetworkInfo.getExtraInfo());
180 | }
181 |
182 | // Src:
183 | // https://github.com/caarmen/network-monitor/blob/master/networkmonitor/src/main/java/ca/rmen/android/networkmonitor/app/service/datasources/CellLocationDataSource.java
184 | private void fromTelephonyManager(Context context) {
185 | // GSM Cell location
186 | CellLocation cellLocation = telephonyManager.getCellLocation();
187 | if (cellLocation instanceof GsmCellLocation) {
188 | GsmCellLocation gsmCellLocation = (GsmCellLocation) cellLocation;
189 | int cid = gsmCellLocation.getCid();
190 | // The javadoc says the cell id should be less than FFFF, but this
191 | // isn't always so. We'll report both the full cell id returned by
192 | // Android, and the truncated one (taking only the last 2 bytes).
193 | int shortCid = cid > 0 ? cid & 0xFFFF : cid;
194 | int rnc = cid > 0 ? cid >> 16 & 0xFFFF : 0;
195 | editor.putInt(PREFS_GSM_FULL_CELL_ID, cid);
196 | if (rnc > 0)
197 | editor.putInt(PREFS_GSM_RNC, rnc);
198 | editor.putInt(PREFS_GSM_SHORT_CELL_ID, shortCid);
199 | editor.putInt(PREFS_GSM_CELL_LAC, gsmCellLocation.getLac());
200 | }
201 | editor.putString(PREFS_SIM_OPERATOR,
202 | telephonyManager.getNetworkOperatorName());
203 | }
204 |
205 | // Src:
206 | // https://github.com/caarmen/network-monitor/blob/master/networkmonitor/src/main/java/ca/rmen/android/networkmonitor/app/service/datasources/WiFiDataSource.java
207 | private void fromWifiManager(Context context) {
208 | WifiInfo connectionInfo = wifiManager.getConnectionInfo();
209 | if (connectionInfo == null || connectionInfo.getNetworkId() < 0)
210 | return;
211 |
212 | editor.putString(PREFS_WIFI_SSID, connectionInfo.getSSID());
213 | String bssid = connectionInfo.getBSSID();
214 | editor.putString(PREFS_WIFI_BSSID, bssid);
215 | int signalLevel = WifiManager.calculateSignalLevel(
216 | connectionInfo.getRssi(), 5);
217 | editor.putInt(PREFS_WIFI_SIGNAL_4, signalLevel);
218 | editor.putInt(PREFS_WIFI_SIGNAL_RSSI, connectionInfo.getRssi());
219 | editor.putInt(PREFS_WIFI_SPEED, connectionInfo.getLinkSpeed());
220 | editor.putString(PREFS_WIFI_STATE, getWifiState());
221 |
222 | List scanResults = wifiManager.getScanResults();
223 | if (scanResults != null) {
224 | for (ScanResult scanResult : scanResults) {
225 | if (scanResult.BSSID != null && scanResult.BSSID.equals(bssid)) {
226 | editor.putInt(PREFS_WIFI_FREQ, scanResult.frequency);
227 | break;
228 | }
229 | }
230 | }
231 | }
232 |
233 | private String getWifiState() {
234 | int state = wifiManager.getWifiState();
235 | switch (state) {
236 | case WifiManager.WIFI_STATE_DISABLED:
237 | return "Disabled";
238 | case WifiManager.WIFI_STATE_DISABLING:
239 | return "Disabling";
240 | case WifiManager.WIFI_STATE_ENABLED:
241 | return "Enabled";
242 | case WifiManager.WIFI_STATE_ENABLING:
243 | return "Enabling";
244 | case WifiManager.WIFI_STATE_UNKNOWN:
245 | return "Unknown";
246 | }
247 | return "Error";
248 | }
249 |
250 | private void fromPhoneState() {
251 | editor.putString(PREFS_CELL_TYPE, phoneState.getNetworkType());
252 | editor.putString(PREFS_SIM_STATE, phoneState.getSimState());
253 | editor.putString(PREFS_DATA_STATE, phoneState.getDataState());
254 | editor.putString(PREFS_DATA_ACTIVITY, phoneState.getDataActivity());
255 |
256 | editor.putInt(PREFS_CELL_SIGNAL_4, phoneState.getLastSignalStrength());
257 | int dBm = phoneState.getLastSignalStrengthDbm();
258 | if (dBm != 0)
259 | editor.putInt(PREFS_CELL_SIGNAL_DBM, dBm);
260 | int lastBer = phoneState.getLastBer();
261 | if (lastBer >= 0 && lastBer <= 7 || lastBer == 99)
262 | editor.putInt(PREFS_CELL_BER, lastBer);
263 | }
264 |
265 | private void fromLocationState() {
266 | Location lastLocation = locationState.getLastLocation();
267 | if (lastLocation == null)
268 | return;
269 |
270 | editor.putFloat(PREFS_POS_LATITUDE, (float) lastLocation.getLatitude());
271 | editor.putFloat(PREFS_POS_LONGITUDE,
272 | (float) lastLocation.getLongitude());
273 | editor.putFloat(PREFS_POS_ACCURACY, lastLocation.getAccuracy());
274 | editor.putFloat(PREFS_POS_SPEED, lastLocation.getSpeed());
275 | }
276 |
277 | // Src: https://github.com/caarmen/network-monitor/blob/master/networkmonitor/src/main/java/ca/rmen/android/networkmonitor/app/service/datasources/NetworkInterfaceDataSource.java
278 | private void fromNetworkInterface() {
279 |
280 | List activeIfaces = IPRouteUtils.getActiveIfaces();
281 | if (activeIfaces == null || activeIfaces.isEmpty())
282 | return;
283 |
284 | StringBuffer ifacesNames = new StringBuffer();
285 | StringBuffer ipv4WiFi = new StringBuffer();
286 | StringBuffer ipv4RMNet = new StringBuffer();
287 | StringBuffer ipv6WiFi = new StringBuffer();
288 | StringBuffer ipv6RMNet = new StringBuffer();
289 |
290 | for (NetworkInterface networkInterface : activeIfaces) {
291 | String ifaceName = networkInterface.getName();
292 | ifacesNames.append(";" + ifaceName);
293 | boolean isMobile = IPRouteUtils.isMobile(ifaceName);
294 | Enumeration inetAddresses = networkInterface
295 | .getInetAddresses();
296 | while (inetAddresses.hasMoreElements()) {
297 | InetAddress inetAddress = inetAddresses.nextElement();
298 | StringBuffer ip = null;
299 | if (inetAddress instanceof Inet4Address)
300 | ip = isMobile ? ipv4RMNet : ipv4WiFi;
301 | else if (!inetAddress.isLinkLocalAddress())
302 | ip = isMobile ? ipv6RMNet : ipv6WiFi;
303 | if (ip != null)
304 | ip.append(";" + inetAddress.getHostAddress());
305 | }
306 | }
307 |
308 | if (ifacesNames.length() > 0)
309 | editor.putString(PREFS_IFACES, ifacesNames.substring(1));
310 | if (ipv4WiFi.length() > 0)
311 | editor.putString(PREFS_IP_WIFI_V4, ipv4WiFi.substring(1));
312 | if (ipv4RMNet.length() > 0)
313 | editor.putString(PREFS_IP_RMNET_V4, ipv4RMNet.substring(1));
314 | if (ipv6WiFi.length() > 0)
315 | editor.putString(PREFS_IP_WIFI_V6, ipv6WiFi.substring(1));
316 | if (ipv6RMNet.length() > 0)
317 | editor.putString(PREFS_IP_RMNET_V6, ipv6RMNet.substring(1));
318 | }
319 |
320 | private void fromSystem() {
321 | if (trackingSec)
322 | return;
323 | editor.putString(PREFS_NETSTAT, Cmd.getAllLinesString("netstat", ';')
324 | .replaceAll("\\s+", " "));
325 | editor.putString(PREFS_PROC_MPTCP,
326 | getFileContent("/proc/net/mptcp", ';').replaceAll("\\s+", " "));
327 | editor.putString(PREFS_PROC_MPTCP_FM,
328 | getFileContent("/proc/net/mptcp_fullmesh", ';'));
329 | }
330 |
331 | private static String getFileContent(String path, char sep) {
332 | StringBuffer sBuffer = new StringBuffer();
333 | BufferedReader bReader = null;
334 | String line = null;
335 | try {
336 | bReader = new BufferedReader(new FileReader(path));
337 | while ((line = bReader.readLine()) != null) {
338 | sBuffer.append(line);
339 | sBuffer.append(sep);
340 | }
341 | } catch (IOException e) {
342 | Log.e(Manager.TAG,
343 | "getFileContent(" + path + "): " + e.getMessage());
344 | } finally {
345 | try {
346 | if (bReader != null)
347 | bReader.close();
348 | } catch (IOException ex) {
349 | ex.printStackTrace();
350 | }
351 | }
352 | return sBuffer.toString();
353 | }
354 |
355 | private void fromNetAsync() {
356 | new GetIPTask(editor).execute("myip");
357 | }
358 |
359 | private void fromSettings(Context context) {
360 | if (trackingSec)
361 | return;
362 | try {
363 | editor.putBoolean(PREFS_AIRPLANE, Settings.Global.getInt(
364 | context.getContentResolver(),
365 | Settings.Global.AIRPLANE_MODE_ON) == 1);
366 | } catch (SettingNotFoundException e) {
367 | }
368 | }
369 | }
370 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/stats/StatsCategories.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.stats;
22 |
23 | public enum StatsCategories {
24 | STARTUP, HANDOVER;
25 | }
26 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/system/Cmd.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.system;
22 |
23 | import java.io.BufferedReader;
24 | import java.io.IOException;
25 | import java.io.InputStreamReader;
26 | import java.util.ArrayList;
27 | import java.util.List;
28 |
29 | import android.util.Log;
30 | import be.uclouvain.multipathcontrol.global.Manager;
31 |
32 | public class Cmd {
33 | private Cmd() {
34 | }
35 |
36 | public static Process runAsUser(String cmd) throws Exception {
37 | return Runtime.getRuntime().exec(cmd.split(" "));
38 | }
39 |
40 | public static Process runAsRoot(String cmd) throws Exception {
41 | Log.d(Manager.TAG, "command: " + cmd);
42 | return Runtime.getRuntime().exec(new String[] { "su", "-c", cmd });
43 | }
44 |
45 | public static void runAsRoot(String[] cmds) throws Exception {
46 | for (String cmd : cmds) {
47 | runAsRoot(cmd);
48 | }
49 | }
50 |
51 | public static String getFirstLine(String cmd, boolean root) {
52 | String line;
53 | Process p;
54 | try {
55 | if (root)
56 | p = runAsRoot(cmd);
57 | else
58 | p = runAsUser(cmd);
59 | BufferedReader in = new BufferedReader(new InputStreamReader(
60 | p.getInputStream()));
61 | line = in.readLine();
62 | in.close();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | return null;
66 | } catch (Exception e) {
67 | e.printStackTrace();
68 | return null;
69 | }
70 | return line;
71 | }
72 |
73 | public static String getFirstLine(String cmd) {
74 | return getFirstLine(cmd, false);
75 | }
76 |
77 | public static List getAllLines(String cmd, boolean root) {
78 | List lines = new ArrayList();
79 | String line;
80 | Process p;
81 | BufferedReader in = null;
82 | try {
83 | if (root)
84 | p = runAsRoot(cmd);
85 | else
86 | p = runAsUser(cmd);
87 | in = new BufferedReader(new InputStreamReader(p.getInputStream()));
88 | while ((line = in.readLine()) != null) {
89 | lines.add(line);
90 | }
91 | } catch (Exception e) {
92 | e.printStackTrace();
93 | } finally {
94 | if (in != null)
95 | try {
96 | in.close();
97 | } catch (IOException e) {
98 | }
99 | }
100 | return lines.size() > 0 ? lines : null;
101 | }
102 |
103 | public static List getAllLines(String cmd) {
104 | return getAllLines(cmd, false);
105 | }
106 |
107 | public static String getAllLinesString(String cmd, boolean root, char sep) {
108 | StringBuffer sBuffer = new StringBuffer();
109 | List lines = getAllLines(cmd, root);
110 | for (String line : lines) {
111 | sBuffer.append(line);
112 | sBuffer.append(sep);
113 | }
114 | return sBuffer.toString();
115 | }
116 |
117 | public static String getAllLinesString(String cmd, char sep) {
118 | return getAllLinesString(cmd, false, sep);
119 | }
120 |
121 | public static String getAllLinesString(String cmd, boolean root) {
122 | return getAllLinesString(cmd, root, '\n');
123 | }
124 |
125 | public static String getAllLinesString(String cmd) {
126 | return getAllLinesString(cmd, false, '\n');
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/system/IPRouteUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.system;
22 |
23 | import java.lang.reflect.Method;
24 | import java.net.InetAddress;
25 | import java.net.NetworkInterface;
26 | import java.net.SocketException;
27 | import java.net.UnknownHostException;
28 | import java.nio.ByteBuffer;
29 | import java.util.ArrayList;
30 | import java.util.Enumeration;
31 | import java.util.LinkedList;
32 | import java.util.List;
33 | import java.util.regex.Matcher;
34 | import java.util.regex.Pattern;
35 |
36 | import android.util.Log;
37 | import be.uclouvain.multipathcontrol.global.Config;
38 | import be.uclouvain.multipathcontrol.global.Manager;
39 |
40 | public class IPRouteUtils {
41 |
42 | // TODO: will not work when using 2 SIMs cards...
43 | private static final String DEFAULT_DATA_IFACE = "rmnet0";
44 | private static final String DEFAULT_WLAN_IFACE = "wlan0";
45 | private static final int ipVersions[] = { 4, 6 };
46 |
47 | public static String getDefaultIFace() {
48 | if (Config.defaultRouteData)
49 | return DEFAULT_DATA_IFACE;
50 | else
51 | return DEFAULT_WLAN_IFACE;
52 | }
53 |
54 | public static int mapIfaceToTable(String ifaceName) {
55 | return Math.abs(ifaceName.hashCode()) % 32765 + 1;
56 | }
57 |
58 | public static int mapIfaceToTable(NetworkInterface iface) {
59 | return mapIfaceToTable(iface.getName());
60 | }
61 |
62 | public static int packAddress(InetAddress addr) {
63 | return ByteBuffer.wrap(addr.getAddress()).getInt();
64 | }
65 |
66 | public static InetAddress unpackAddress(int addr)
67 | throws UnknownHostException {
68 | return InetAddress.getByAddress(new byte[] {
69 | (byte) ((addr >>> 24) & 0xff), (byte) ((addr >>> 16) & 0xff),
70 | (byte) ((addr >>> 8) & 0xff), (byte) ((addr) & 0xff) });
71 | }
72 |
73 | /* Return the value of a system property key */
74 | public static String getSystemProperty(String key) {
75 | try {
76 | Class> spClass = Class.forName("android.os.SystemProperties");
77 | Method method = spClass.getDeclaredMethod("get", String.class);
78 | return (String) method.invoke(spClass, key);
79 | } catch (Exception e) {
80 | }
81 | return null;
82 | }
83 |
84 | public static String getGateway(String ifaceName) {
85 | /* Unfortunately there is no clean/easy way to do this in Android :-( */
86 | String gateway = getSystemProperty("net." + ifaceName + ".gw");
87 | gateway = gateway.isEmpty() ? getSystemProperty("dhcp." + ifaceName
88 | + ".gateway") : gateway;
89 | return gateway;
90 | }
91 |
92 | public static String getGateway(NetworkInterface iface) {
93 | return getGateway(iface.getName());
94 | }
95 |
96 | public static InetAddress toSubnet(InetAddress addr, int prefix)
97 | throws UnknownHostException {
98 | int address = packAddress(addr);
99 | int mask = 0xffffffff << (32 - prefix);
100 | int subnet = address & mask;
101 | return unpackAddress(subnet);
102 | }
103 |
104 | public static List> existingRules(int table) {
105 | Pattern pa = Pattern.compile("^([0-9]+):.* lookup " + table + " $");
106 | // We cannot use an array of lists :-)
107 | List> allRules = new ArrayList>(2);
108 |
109 | for (int i = 0; i < ipVersions.length; i++) {
110 | List rules = new ArrayList();
111 | allRules.add(i, rules);
112 | for (String line : Cmd.getAllLines("ip -" + ipVersions[i]
113 | + " rule show")) {
114 | Matcher m = pa.matcher(line);
115 | if (m.matches())
116 | rules.add(Integer.parseInt(m.group(1)));
117 | }
118 | }
119 | return allRules;
120 | }
121 |
122 | public static void resetRule(NetworkInterface iface) {
123 | int table = mapIfaceToTable(iface);
124 | String[] cmds;
125 | /* Unfortunately ip rule delete table X doesn't work :-( */
126 | List> allRules = existingRules(table);
127 |
128 | for (int ip = 0; ip < ipVersions.length; ip++) {
129 | List rules = allRules.get(ip);
130 |
131 | cmds = new String[rules.size() + 1];
132 | cmds[0] = "ip -" + ipVersions[ip] + " route flush table " + table;
133 |
134 | for (int i = 1; i < cmds.length; ++i)
135 | cmds[i] = "ip -" + ipVersions[ip] + " rule delete prio "
136 | + rules.get(i - 1);
137 |
138 | try {
139 | Cmd.runAsRoot(cmds);
140 | } catch (Exception e) {
141 | }
142 | }
143 | }
144 |
145 | public static boolean isMobile(String ifaceName) {
146 | return ifaceName.startsWith("rmnet");
147 | }
148 |
149 | public static boolean isMobile(NetworkInterface iface) {
150 | return isMobile(iface.getName());
151 | }
152 |
153 | public static boolean isIPv6(String hostAddr) {
154 | return hostAddr.contains(":");
155 | }
156 |
157 | public static String getIPVersion(String hostAddr) {
158 | if (isIPv6(hostAddr))
159 | return "-6";
160 | return "-4";
161 | }
162 |
163 | public static String removeScope(String hostAddr) {
164 | if (hostAddr == null)
165 | return null;
166 | int pos = hostAddr.indexOf("%");
167 | if (pos == -1)
168 | return hostAddr;
169 | return hostAddr.substring(0, pos);
170 | }
171 |
172 | public static boolean setDefaultRoute(String iface, String gateway,
173 | boolean withScope) {
174 | if (gateway == null || gateway.isEmpty())
175 | return false;
176 | gateway = removeScope(gateway);
177 | try {
178 | Cmd.runAsRoot("ip " + getIPVersion(gateway)
179 | + " route change default via " + gateway + " dev " + iface);
180 | // if there where no default route
181 | Cmd.runAsRoot("ip " + getIPVersion(gateway)
182 | + " route add default via " + gateway + " dev " + iface);
183 | } catch (Exception e) {
184 | e.printStackTrace();
185 | return false;
186 | }
187 | return true;
188 | }
189 |
190 | public static boolean setDefaultRoute() {
191 | String iface = getDefaultIFace();
192 |
193 | String gateway = getGateway(iface);
194 | return setDefaultRoute(iface, gateway, true);
195 | }
196 |
197 | public static boolean setDataBackup() {
198 | String status;
199 | if (Config.dataBackup)
200 | status = "backup";
201 | else
202 | status = "on";
203 |
204 | try {
205 | Cmd.runAsRoot("ip link set dev " + DEFAULT_DATA_IFACE
206 | + " multipath " + status);
207 | } catch (Exception e) {
208 | return false;
209 | }
210 | return true;
211 | }
212 |
213 | /**
214 | * @return a list of all active interfaces (up, not loopback, with IP)
215 | */
216 | public static List getActiveIfaces() {
217 | Enumeration networkInterfaces;
218 | try {
219 | networkInterfaces = NetworkInterface.getNetworkInterfaces();
220 | } catch (SocketException e) {
221 | Log.w(Manager.TAG, "Not able to get Network Interfaces");
222 | return null;
223 | }
224 |
225 | List activeIfaces = new LinkedList<>();
226 | while (networkInterfaces.hasMoreElements()) {
227 | NetworkInterface networkInterface = networkInterfaces.nextElement();
228 | // all active interface, not loopback
229 | try {
230 | if (networkInterface.isUp() && !networkInterface.isLoopback()) {
231 | Enumeration inetAddresses = networkInterface
232 | .getInetAddresses();
233 | // only if it has address
234 | if (inetAddresses.hasMoreElements())
235 | activeIfaces.add(networkInterface);
236 | }
237 | } catch (SocketException e) {
238 | }
239 | }
240 |
241 | return activeIfaces;
242 | }
243 | }
244 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/system/Sysctl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.system;
22 |
23 | import java.io.BufferedReader;
24 | import java.io.FileReader;
25 | import java.io.IOException;
26 |
27 | public class Sysctl {
28 |
29 | private static final String BASE = "/proc/sys";
30 |
31 | private Sysctl() {
32 | }
33 |
34 | public static String getSysctl(String key) {
35 | // String line = Cmd.getFirstLine("sysctl " + key); // busybox is needed
36 | String path = BASE + '/' + key.replace('.', '/');
37 | BufferedReader br = null;
38 | String line = null;
39 | try {
40 | br = new BufferedReader(new FileReader(path));
41 | line = br.readLine();
42 | } catch (IOException e) {
43 | e.printStackTrace();
44 | } finally {
45 | try {
46 | if (br != null)
47 | br.close();
48 | } catch (IOException ex) {
49 | ex.printStackTrace();
50 | }
51 | }
52 | if (line == null || line.isEmpty())
53 | return null;
54 | return line;
55 | }
56 |
57 | public static boolean setSysctl(String key, String value) {
58 | int rc = 1;
59 | try {
60 | String path = BASE + '/' + key.replace('.', '/');
61 | rc = Cmd.runAsRoot("echo " + value + " > " + path).waitFor();
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | return false;
65 | }
66 | return rc == 0; // delayed... getSysctl(key).equals(value);
67 | }
68 |
69 | public static String[] getAvailableCC() {
70 | String line = getSysctl("net.ipv4.tcp_available_congestion_control");
71 | if (line == null)
72 | return new String[] { "Error" };
73 | return line.split(" ");
74 | }
75 |
76 | public static String getCC() {
77 | return getSysctl("net.ipv4.tcp_congestion_control");
78 | }
79 |
80 | public static boolean setCC(String value) {
81 | return setSysctl("net.ipv4.tcp_congestion_control", value);
82 | }
83 |
84 | public static boolean getIPv6() {
85 | return getSysctl("net.ipv6.conf.all.disable_ipv6").equals("0");
86 | }
87 |
88 | public static boolean setIPv6(boolean ipv6, String iface) {
89 | String rules = ipv6 ? "ACCEPT" : "DROP";
90 | try {
91 | Cmd.runAsRoot(new String[] {
92 | "ip6tables -P INPUT " + rules,
93 | "ip6tables -P OUPUT " + rules,
94 | "ip6tables -P FORWARD " + rules });
95 | } catch (Exception e) {
96 | e.printStackTrace();
97 | }
98 | return setSysctl("net.ipv6.conf." + iface + ".disable_ipv6", ipv6 ? "0"
99 | : "1");
100 | }
101 |
102 | public static boolean setIPv6(boolean ipv6) {
103 | return setIPv6(ipv6, "all");
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/MultipathControl/src/be/uclouvain/multipathcontrol/ui/Notifications.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of MultipathControl.
3 | *
4 | * Copyright 2012 UCLouvain - Gregory Detal
5 | * Copyright 2015 UCLouvain - Matthieu Baerts
6 | *
7 | * MultipathControl is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | package be.uclouvain.multipathcontrol.ui;
22 |
23 | import android.app.Notification;
24 | import android.app.NotificationManager;
25 | import android.app.PendingIntent;
26 | import android.content.Context;
27 | import android.content.Intent;
28 | import be.uclouvain.multipathcontrol.R;
29 | import be.uclouvain.multipathcontrol.activities.MainActivity;
30 |
31 | public class Notifications {
32 |
33 | private final NotificationManager mNotification;
34 | private final Context context;
35 |
36 | public Notifications(Context context) {
37 | this.context = context;
38 | mNotification = (NotificationManager) context
39 | .getSystemService(Context.NOTIFICATION_SERVICE);
40 | }
41 |
42 | public void showNotification() {
43 | Intent intent = new Intent(context, MainActivity.class);
44 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 1,
45 | intent, 0);
46 |
47 | Notification notif = new Notification.Builder(context)
48 | .setWhen(System.currentTimeMillis())
49 | .setSmallIcon(R.drawable.ic_launcher)
50 | .setContentTitle(
51 | context.getResources().getString(
52 | R.string.notification_title))
53 | .setContentText(
54 | context.getResources().getString(
55 | R.string.notification_text))
56 | .setContentIntent(pendingIntent).build();
57 |
58 | notif.flags |= Notification.FLAG_NO_CLEAR;
59 |
60 | mNotification.notify(1, notif);
61 | }
62 |
63 | public void hideNotification() {
64 | NotificationManager mNotification = (NotificationManager) context
65 | .getSystemService(Context.NOTIFICATION_SERVICE);
66 | mNotification.cancelAll();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | MultipathControl
2 | ================
3 |
4 | GUI to manage MPTCP settings and log statistics on Android devices.
5 |
6 | APK
7 | ---
8 |
9 | APK are available on [Releases](https://github.com/MPTCP-smartphone-thesis/MultipathControl/releases) section.
10 |
11 | Credits
12 | -------
13 |
14 | This project was initially created by Gregory Detal (http://github.com/gdetal),
15 | but most of the current code was contributed by Matthieu Baerts (http://github.com/matttbe)
16 | and Quentin De Coninck (http://github.com/qdeconinck) for a thesis about MPTCP and Smartphones
17 | and supervised by Pr. O. Bonaventure (http://github.com/obonaventure).
18 |
19 | Thanks to Carmen Alvarez for his Network-Monitor project! It was useful for the logging part.
20 | https://github.com/caarmen/network-monitor/ (Licensed under the Apache License, Version 2.0)
21 |
22 | Licence
23 | -------
24 |
25 | This program is free software: you can redistribute it and/or modify
26 | it under the terms of the GNU General Public License as published by
27 | the Free Software Foundation, either version 3 of the License, or
28 | (at your option) any later version.
29 |
30 | This program is distributed in the hope that it will be useful,
31 | but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 | GNU General Public License for more details.
34 |
35 | You should have received a copy of the GNU General Public License
36 | along with this program. If not, see .
37 |
--------------------------------------------------------------------------------