diff --git a/app/app.iml b/app/app.iml
index c123b6e..64848e5 100644
--- a/app/app.iml
+++ b/app/app.iml
@@ -65,32 +65,25 @@
-
-
-
-
+
-
-
-
-
-
-
+
+
-
+
-
-
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 5b8dcb8..2fd34c0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,15 +1,15 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 22
- buildToolsVersion "22.0.0"
+ compileSdkVersion 23
+ buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.mridang.speedo"
- minSdkVersion 14
- targetSdkVersion 22
- versionCode 1
- versionName "1.0"
+ minSdkVersion 16
+ targetSdkVersion 23
+ versionCode 2
+ versionName "1.1"
}
buildTypes {
release {
@@ -21,6 +21,6 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
- compile 'com.android.support:support-v4:22.1.1'
+ compile 'com.android.support:support-v4:23.1.1'
compile project(':colorPicker')
-}
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index af83aa7..f3b54e5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -38,6 +38,21 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/mridang/speedo/BatteryReceiver.java b/app/src/main/java/com/mridang/speedo/BatteryReceiver.java
new file mode 100644
index 0000000..35a6362
--- /dev/null
+++ b/app/src/main/java/com/mridang/speedo/BatteryReceiver.java
@@ -0,0 +1,32 @@
+package com.mridang.speedo;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * Broadcast receiver class to help start or stop the traffic monitoring service when the phone's
+ * battery level is low or okay.
+ */
+public class BatteryReceiver extends BroadcastReceiver {
+
+ /**
+ * Receiver method for the phone boot that starts the traffic monitoring service
+ */
+ @Override
+ public void onReceive(Context appContext, Intent ittIntent) {
+ Log.v("BatteryReceiver", "Received a battery intent");
+ if (PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("enabled", true) &&
+ PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("lowpower", false)) {
+ if (ittIntent.getAction().equals(Intent.ACTION_BATTERY_LOW)) {
+ Log.i("BatteryReceiver", "Battery low. Stopping service");
+ appContext.stopService(new Intent(appContext, TrafficService.class));
+ } else {
+ Log.i("BatteryReceiver", "Battery okay. Starting service");
+ appContext.startService(new Intent(appContext, TrafficService.class));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mridang/speedo/BootReceiver.java b/app/src/main/java/com/mridang/speedo/BootReceiver.java
index 904d3fe..5b997a2 100644
--- a/app/src/main/java/com/mridang/speedo/BootReceiver.java
+++ b/app/src/main/java/com/mridang/speedo/BootReceiver.java
@@ -6,18 +6,18 @@ import android.content.Intent;
import android.preference.PreferenceManager;
/**
- Broadcast receiver class to help start the traffic monitoring service when the phone boots up only
- if the service is enabled.
+ * Broadcast receiver class to help start the traffic monitoring service when the phone boots up only
+ * if the service is enabled.
*/
public class BootReceiver extends BroadcastReceiver {
- /**
- Receiver method for the phone boot that starts the traffic monitoring service
- */
- @Override
- public void onReceive(Context appContext, Intent bootIntent) {
- if (PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("enabled", true)) {
- appContext.startService(new Intent(appContext, TrafficService.class));
- }
- }
+ /**
+ * Receiver method for the phone boot that starts the traffic monitoring service
+ */
+ @Override
+ public void onReceive(Context appContext, Intent bootIntent) {
+ if (PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("enabled", true)) {
+ appContext.startService(new Intent(appContext, TrafficService.class));
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/mridang/speedo/PowerReceiver.java b/app/src/main/java/com/mridang/speedo/PowerReceiver.java
new file mode 100644
index 0000000..8b16e60
--- /dev/null
+++ b/app/src/main/java/com/mridang/speedo/PowerReceiver.java
@@ -0,0 +1,37 @@
+package com.mridang.speedo;
+
+import android.annotation.TargetApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.PowerManager;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+/**
+ * Broadcast receiver class to help start or stop the traffic monitoring service when the phone's
+ * battery saver mode is enabled or disabled
+ */
+public class PowerReceiver extends BroadcastReceiver {
+
+ /**
+ * Receiver method for the phone boot that starts the traffic monitoring service
+ */
+ @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+ @Override
+ public void onReceive(Context appContext, Intent bootIntent) {
+ Log.v("BatteryReceiver", "Received a power intent");
+ if (PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("enabled", true) &&
+ PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("lowpower", false)) {
+ PowerManager mgrPower = (PowerManager) appContext.getSystemService(Context.POWER_SERVICE);
+ if (mgrPower.isPowerSaveMode()) {
+ Log.i("BatteryReceiver", "Power saving mode enabled. Stopping service");
+ appContext.stopService(new Intent(appContext, TrafficService.class));
+ } else {
+ Log.i("BatteryReceiver", "Power saving mode disabled. Starting service");
+ appContext.startService(new Intent(appContext, TrafficService.class));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mridang/speedo/SettingsActivity.java b/app/src/main/java/com/mridang/speedo/SettingsActivity.java
index aaf9e90..1b37eb2 100644
--- a/app/src/main/java/com/mridang/speedo/SettingsActivity.java
+++ b/app/src/main/java/com/mridang/speedo/SettingsActivity.java
@@ -9,106 +9,106 @@ import android.preference.Preference;
import android.preference.PreferenceActivity;
/**
- Settings activity that allows the user to start or stop the service and also change the polling
- interval
+ * Settings activity that allows the user to start or stop the service and also change the polling
+ * interval
*/
public class SettingsActivity extends PreferenceActivity {
- private boolean isBounded;
- private TrafficService backgroundService;
+ private boolean isBounded;
+ private TrafficService backgroundService;
- /**
- Connection class between the activity and the service to be able to invoke service methods
- */
- private final ServiceConnection mConnection = new ServiceConnection() {
+ /**
+ * Connection class between the activity and the service to be able to invoke service methods
+ */
+ private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceDisconnected(ComponentName name) {
- isBounded = false;
- backgroundService = null;
- }
+ public void onServiceDisconnected(ComponentName name) {
+ isBounded = false;
+ backgroundService = null;
+ }
- public void onServiceConnected(ComponentName name, IBinder service) {
- isBounded = true;
- TrafficService.LocalBinder mLocalBinder = (TrafficService.LocalBinder) service;
- backgroundService = mLocalBinder.getServerInstance();
- }
- };
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ isBounded = true;
+ TrafficService.LocalBinder mLocalBinder = (TrafficService.LocalBinder) service;
+ backgroundService = mLocalBinder.getServerInstance();
+ }
+ };
- /**
- OnStart method of the activity that establishes a connection with the service by binding to it
- */
- @Override
- protected void onStart() {
- super.onStart();
- Intent serviceIntent = new Intent(getApplicationContext(), TrafficService.class);
- startService(serviceIntent);
- bindService(serviceIntent, mConnection, BIND_AUTO_CREATE);
- }
+ /**
+ * OnStart method of the activity that establishes a connection with the service by binding to it
+ */
+ @Override
+ protected void onStart() {
+ super.onStart();
+ Intent serviceIntent = new Intent(getApplicationContext(), TrafficService.class);
+ startService(serviceIntent);
+ bindService(serviceIntent, mConnection, BIND_AUTO_CREATE);
+ }
- /**
- OnStop method of the activity that destroys the connection with the service by unbinding from
- it
- */
- @Override
- protected void onStop() {
- super.onStop();
- if (isBounded) {
- unbindService(mConnection);
- isBounded = false;
- }
- }
+ /**
+ * OnStop method of the activity that destroys the connection with the service by unbinding from
+ * it
+ */
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (isBounded) {
+ unbindService(mConnection);
+ isBounded = false;
+ }
+ }
- /**
- Post create method that bind each of the preferences to a listener so that updating the
- preferences will fire the listeners to trigger updates to the notification
- */
- @SuppressWarnings("deprecation")
- @Override
- protected void onPostCreate(Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.preferences);
+ /**
+ * Post create method that bind each of the preferences to a listener so that updating the
+ * preferences will fire the listeners to trigger updates to the notification
+ */
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences);
- findPreference("enabled").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ findPreference("enabled").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- /**
- * Preference change listener that handles the starting and the stopping of the service
- * depending on whether the the switch is toggled or not.
- */
- @Override
- public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
- if ((Boolean) newValue) {
- backgroundService.showNotification();
- } else {
- backgroundService.hideNotification();
- }
- return true;
- }
- });
+ /**
+ * Preference change listener that handles the starting and the stopping of the service
+ * depending on whether the the switch is toggled or not.
+ */
+ @Override
+ public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
+ if ((Boolean) newValue) {
+ backgroundService.showNotification();
+ } else {
+ backgroundService.hideNotification();
+ }
+ return true;
+ }
+ });
- findPreference("lockscreen").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ findPreference("lockscreen").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- /**
- * Preference change listener that handles whether the notification should be displayed
- * on the lockscreen depending on whether the the switch is toggled or not.
- */
- @Override
- public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
- backgroundService.visibilityPublic((Boolean) newValue);
- return true;
- }
- });
+ /**
+ * Preference change listener that handles whether the notification should be displayed
+ * on the lockscreen depending on whether the the switch is toggled or not.
+ */
+ @Override
+ public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
+ backgroundService.visibilityPublic((Boolean) newValue);
+ return true;
+ }
+ });
- findPreference("color").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ findPreference("color").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- /**
- * Preference change listener that handles whether the notification should be displayed
- * on the lockscreen depending on whether the the switch is toggled or not.
- */
- @Override
- public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
- backgroundService.setColor((Integer) newValue);
- return true;
- }
- });
- }
+ /**
+ * Preference change listener that handles whether the notification should be displayed
+ * on the lockscreen depending on whether the the switch is toggled or not.
+ */
+ @Override
+ public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
+ backgroundService.setColor((Integer) newValue);
+ return true;
+ }
+ });
+ }
}
diff --git a/app/src/main/java/com/mridang/speedo/TrafficService.java b/app/src/main/java/com/mridang/speedo/TrafficService.java
index 0efc722..7bc99ac 100644
--- a/app/src/main/java/com/mridang/speedo/TrafficService.java
+++ b/app/src/main/java/com/mridang/speedo/TrafficService.java
@@ -17,9 +17,11 @@ import android.net.TrafficStats;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Binder;
+import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.telephony.TelephonyManager;
@@ -27,334 +29,344 @@ import android.text.format.Formatter;
import android.util.Log;
/**
- Main service class that monitors the network speed and updates the notification every second
+ * Main service class that monitors the network speed and updates the notification every second
*/
public class TrafficService extends Service {
- /**
- Custom binder class used for allowing the preference activity to bind to this service so that it
- may be configured on the fly
- */
- public class LocalBinder extends Binder {
+ /**
+ * The constant defining the identifier of the notification that is to be shown
+ */
+ private static final int ID = 9000;
+ /**
+ * The identifier if the component that open from the settings activity
+ */
+ private static final String CMP = "com.android.settings.Settings$DataUsageSummaryActivity";
+ /**
+ * The instance of the handler that updates the notification
+ */
+ private static NotificationHandler hndNotifier;
+ /**
+ * The instance of the manager of the connectivity services
+ */
+ private static ConnectivityManager mgrConnectivity;
+ /**
+ * The instance of the manager of the notification services
+ */
+ private static NotificationManager mgrNotifications;
+ /**
+ * The instance of the manager of the wireless services
+ */
+ private static WifiManager mgrWireless;
+ /**
+ * The instance of the manager of the telephony services
+ */
+ private static TelephonyManager mgrTelephony;
+ /**
+ * The instance of the notification builder to rebuild the notification
+ */
+ private static NotificationCompat.Builder notBuilder;
+ /**
+ * The instance of the binder class used by the activity
+ */
+ private final IBinder mBinder = new LocalBinder();
+ /**
+ * The instance of the broadcast receiver to handle intents
+ */
+ private BroadcastReceiver recScreen;
+ /**
+ * The instance of the broadcast receiver to handle power saver mode intents
+ */
+ private final BroadcastReceiver recSaver = new PowerReceiver();
- public TrafficService getServerInstance() {
- return TrafficService.this;
- }
- }
+ /**
+ * Initializes the service by getting instances of service managers and mainly setting up the
+ * receiver to receive all the necessary intents that this service is supposed to handle.
+ */
+ @Override
+ public void onCreate() {
- /**
- The instance of the binder class used by the activity
- */
- private final IBinder mBinder = new LocalBinder();
- /**
- The constant defining the identifier of the notification that is to be shown
- */
- private static final int ID = 9000;
- /**
- The identifier if the component that open from the settings activity
- */
- private static final String CMP = "com.android.settings.Settings$DataUsageSummaryActivity";
+ Log.i("HardwareService", "Creating the hardware service");
+ super.onCreate();
+ final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- /**
- The handler class that runs every second to update the notification with the network speed. It
- also runs every minute to save the amount of data-transferred to the preferences.
- */
- private static class NotificationHandler extends Handler {
+ Intent ittSettings = new Intent();
+ ittSettings.setComponent(new ComponentName("com.android.settings", CMP));
+ PendingIntent pitSettings = PendingIntent.getActivity(this, 0, ittSettings, 0);
+ notBuilder = new NotificationCompat.Builder(this);
+ notBuilder.setSmallIcon(R.drawable.wkb000);
+ notBuilder.setContentIntent(pitSettings);
+ notBuilder.setOngoing(true);
+ notBuilder.setWhen(0);
+ notBuilder.setOnlyAlertOnce(true);
+ notBuilder.setPriority(Integer.MAX_VALUE);
+ notBuilder.setCategory(NotificationCompat.CATEGORY_SERVICE);
+ setColor(settings.getInt("color", Color.TRANSPARENT));
+ visibilityPublic(settings.getBoolean("lockscreen", true));
- /**
- The value of the amount of data transferred in the previous invocation of the method
- */
- private long lngPrevious = 0L;
- /**
- The instance of the context of the parent service
- */
- private final Context ctxContext;
+ Log.d("HardwareService", "Setting up the service manager and the broadcast receiver");
+ mgrConnectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
+ mgrNotifications = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ mgrWireless = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+ mgrTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+ hndNotifier = new NotificationHandler(getApplicationContext());
- /**
- Simple constructor to initialize the initial value of the previous
- */
- @SuppressLint("CommitPrefEdits")
- public NotificationHandler(Context ctxContext) {
- this.ctxContext = ctxContext;
- }
+ if (settings.getBoolean("enabled", true)) {
+ Log.d("HardwareService", "Screen on; showing the notification");
+ hndNotifier.sendEmptyMessage(1);
+ }
+ recScreen = new BroadcastReceiver() {
- /**
- Handler method that updates the notification icon with the current speed. It is a very
- hackish method. We have icons for 1 KB/s to 999 KB/s and 1.0 MB/s to 99.9 MB/s. Every time
- the method is invoked, we get the amount of data transferred. By subtracting this value with
- the previous value, we get the delta. Since this method is invoked every second, this delta
- value indicates the b/s. However, we need to convert this value into KB/s for values under 1
- MB/s and we need to convert the value to MB/s for values over 1 MB/s. Since all our icon
- images are numbered sequentially we can assume that the R class generated will contain the
- integer references of the drawables in the sequential order.
- */
- @Override
- public void handleMessage(Message msgMessage) {
+ /**
+ * Handles the screen-on and the screen off intents to enable or disable the notification.
+ * We don't want to show the notification if the screen is off.
+ */
+ @Override
+ public void onReceive(Context ctcContext, Intent ittIntent) {
- TrafficService.hndNotifier.sendEmptyMessageDelayed(1, 1000L);
+ if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_OFF)) {
- long lngCurrent = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();
- int lngSpeed = (int) (lngCurrent - lngPrevious);
- lngPrevious = lngCurrent;
+ Log.d("TrafficService", "Screen off; hiding the notification");
+ hndNotifier.removeMessages(1);
+ mgrNotifications.cancel(ID);
+ } else if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_ON)) {
- try {
+ Log.d("TrafficService", "Screen on; showing the notification");
+ connectivityUpdate();
+ } else if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
- if (lngSpeed < 1024) {
- TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000);
- } else if (lngSpeed < 1048576L) {
+ if (ittIntent.getBooleanExtra("state", false)) {
- TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000 + (int) (lngSpeed / 1024L));
- if (lngSpeed > 1022976) {
- TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000 + 1000);
- }
- } else if (lngSpeed <= 10485760) {
- TrafficService.notBuilder.setSmallIcon(990 + R.drawable.wkb000
- + (int) (0.5D + (double) (10F * ((float) lngSpeed / 1048576F))));
- } else if (lngSpeed <= 103809024) {
- TrafficService.notBuilder.setSmallIcon(1080 + R.drawable.wkb000
- + (int) (0.5D + (double) ((float) lngSpeed / 1048576F)));
- } else {
- TrafficService.notBuilder.setSmallIcon(1180 + R.drawable.wkb000);
- }
+ Log.d("TrafficService", "Airplane mode; hiding the notification");
+ hndNotifier.removeMessages(1);
+ hndNotifier.sendEmptyMessage(1);
+ } else {
- Long lngTotal = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();
- String strTotal = Formatter.formatFileSize(this.ctxContext, lngTotal);
- TrafficService.notBuilder.setContentInfo(strTotal);
- TrafficService.mgrNotifications.notify(ID, TrafficService.notBuilder.build());
- } catch (Exception e) {
- Log.e("NotificationHandler", "Error creating notification for speed " + lngSpeed);
- }
- }
- }
+ Log.d("TrafficService", "Airplane mode; showing the notification");
+ connectivityUpdate();
+ }
+ } else {
- /**
- The instance of the handler that updates the notification
- */
- private static NotificationHandler hndNotifier;
- /**
- The instance of the manager of the connectivity services
- */
- private static ConnectivityManager mgrConnectivity;
- /**
- The instance of the manager of the notification services
- */
- private static NotificationManager mgrNotifications;
- /**
- The instance of the manager of the wireless services
- */
- private static WifiManager mgrWireless;
- /**
- The instance of the manager of the telephony services
- */
- private static TelephonyManager mgrTelephony;
- /**
- The instance of the notification builder to rebuild the notification
- */
- private static NotificationCompat.Builder notBuilder;
- /**
- The instance of the broadcast receiver to handle intents
- */
- private BroadcastReceiver recScreen;
+ Log.d("TrafficService", "Connectivity change; updating the notification");
+ connectivityUpdate();
+ }
+ }
+ };
- /**
- Initializes the service by getting instances of service managers and mainly setting up the
- receiver to receive all the necessary intents that this service is supposed to handle.
- */
- @Override
- public void onCreate() {
+ IntentFilter ittScreen = new IntentFilter();
+ ittScreen.addAction(Intent.ACTION_SCREEN_ON);
+ ittScreen.addAction(Intent.ACTION_SCREEN_OFF);
+ ittScreen.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ ittScreen.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ registerReceiver(recScreen, ittScreen);
- Log.i("HardwareService", "Creating the hardware service");
- super.onCreate();
- final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ IntentFilter ittSaver = new IntentFilter();
+ ittScreen.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ registerReceiver(recSaver, ittSaver);
+ }
+ }
- Intent ittSettings = new Intent();
- ittSettings.setComponent(new ComponentName("com.android.settings", CMP));
- PendingIntent pitSettings = PendingIntent.getActivity(this, 0, ittSettings, 0);
- notBuilder = new NotificationCompat.Builder(this);
- notBuilder.setSmallIcon(R.drawable.wkb000);
- notBuilder.setContentIntent(pitSettings);
- notBuilder.setOngoing(true);
- notBuilder.setWhen(0);
- notBuilder.setOnlyAlertOnce(true);
- notBuilder.setPriority(Integer.MAX_VALUE);
- notBuilder.setCategory(NotificationCompat.CATEGORY_SERVICE);
- setColor(settings.getInt("color", Color.TRANSPARENT));
- visibilityPublic(settings.getBoolean("lockscreen", true));
+ /**
+ * Updates the notification with the new connectivity information. This method determines the type
+ * of connectivity and updates the notification with the network type and name. If there is no
+ * information about the active network, this will suppress the notification.
+ */
+ private void connectivityUpdate() {
- Log.d("HardwareService", "Setting up the service manager and the broadcast receiver");
- mgrConnectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- mgrNotifications = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
- mgrWireless = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- mgrTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
- hndNotifier = new NotificationHandler(getApplicationContext());
+ NetworkInfo nifNetwork = mgrConnectivity.getActiveNetworkInfo();
+ if (nifNetwork != null && nifNetwork.isConnectedOrConnecting()) {
- if (settings.getBoolean("enabled", true)) {
- Log.d("HardwareService", "Screen on; showing the notification");
- hndNotifier.sendEmptyMessage(1);
- }
- recScreen = new BroadcastReceiver() {
+ Log.d("TrafficService", "Network connected; showing the notification");
+ if (nifNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
- /**
- * Handles the screen-on and the screen off intents to enable or disable the notification.
- * We don't want to show the notification if the screen is off.
- */
- @Override
- public void onReceive(Context ctcContext, Intent ittIntent) {
+ Log.d("TrafficService", "Connected to a wireless network");
+ WifiInfo wifInfo = mgrWireless.getConnectionInfo();
+ if (wifInfo != null && !wifInfo.getSSID().trim().isEmpty()) {
- if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_OFF)) {
+ Log.d("TrafficService", wifInfo.getSSID());
+ notBuilder.setContentTitle(getString(R.string.wireless));
+ notBuilder.setContentText(wifInfo.getSSID().replaceAll("^\"|\"$", ""));
+ showNotification();
+ } else {
- Log.d("TrafficService", "Screen off; hiding the notification");
- hndNotifier.removeMessages(1);
- mgrNotifications.cancel(ID);
- } else if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_ON)) {
+ Log.d("TrafficService", "Unknown network without SSID");
+ hideNotification();
+ }
+ } else {
- Log.d("TrafficService", "Screen on; showing the notification");
- connectivityUpdate();
- } else if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
+ Log.d("TrafficService", "Connected to a cellular network");
+ if (!mgrTelephony.getNetworkOperatorName().trim().isEmpty()) {
- if (ittIntent.getBooleanExtra("state", false)) {
+ Log.d("TrafficService", mgrTelephony.getNetworkOperatorName());
+ notBuilder.setContentTitle(getString(R.string.cellular));
+ notBuilder.setContentText(mgrTelephony.getNetworkOperatorName());
+ showNotification();
+ } else {
- Log.d("TrafficService", "Airplane mode; hiding the notification");
- hndNotifier.removeMessages(1);
- hndNotifier.sendEmptyMessage(1);
- } else {
+ Log.d("TrafficService", "Unknown network without IMSI");
+ hideNotification();
+ }
+ }
+ } else {
- Log.d("TrafficService", "Airplane mode; showing the notification");
- connectivityUpdate();
- }
- } else {
+ Log.d("TrafficService", "Network disconnected; hiding the notification");
+ hideNotification();
+ }
+ }
- Log.d("TrafficService", "Connectivity change; updating the notification");
- connectivityUpdate();
- }
- }
- };
+ /**
+ * Called when the service is being stopped. It doesn't do much except clear the message queue of
+ * the handler, hides the notification and unregisters the receivers.
+ */
+ @Override
+ public void onDestroy() {
- IntentFilter ittScreen = new IntentFilter();
- ittScreen.addAction(Intent.ACTION_SCREEN_ON);
- ittScreen.addAction(Intent.ACTION_SCREEN_OFF);
- ittScreen.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- ittScreen.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- registerReceiver(recScreen, ittScreen);
- }
+ Log.d("HardwareService", "Stopping the hardware service");
+ unregisterReceiver(recScreen);
+ unregisterReceiver(recSaver);
+ hndNotifier.removeMessages(1);
+ mgrNotifications.cancel(ID);
+ }
- /**
- Updates the notification with the new connectivity information. This method determines the type
- of connectivity and updates the notification with the network type and name. If there is no
- information about the active network, this will suppress the notification.
- */
- private void connectivityUpdate() {
+ /**
+ * Helper method that shows the notification by sending the handler a message and building the
+ * notification. This is invoked when the preference is toggled.
+ */
+ public void showNotification() {
- NetworkInfo nifNetwork = mgrConnectivity.getActiveNetworkInfo();
- if (nifNetwork != null && nifNetwork.isConnectedOrConnecting()) {
+ Log.d("HardwareService", "Showing the notification");
+ mgrNotifications.notify(ID, notBuilder.build());
+ hndNotifier.removeMessages(1);
+ hndNotifier.sendEmptyMessage(1);
+ }
- Log.d("TrafficService", "Network connected; showing the notification");
- if (nifNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
+ /**
+ * Helper method that hides the notification by clearing the handler messages and cancelling the
+ * notification. This is invoked when the preference is toggled.
+ */
+ public void hideNotification() {
- Log.d("TrafficService", "Connected to a wireless network");
- WifiInfo wifInfo = mgrWireless.getConnectionInfo();
- if (wifInfo != null && !wifInfo.getSSID().trim().isEmpty()) {
+ Log.d("HardwareService", "Hiding the notification");
+ mgrNotifications.cancel(ID);
+ hndNotifier.removeMessages(1);
+ }
- Log.d("TrafficService", wifInfo.getSSID());
- notBuilder.setContentTitle(getString(R.string.wireless));
- notBuilder.setContentText(wifInfo.getSSID().replaceAll("^\"|\"$", ""));
- showNotification();
- } else {
+ /**
+ * Helper method that toggles the visibility of the notification on the locksreen depending on the
+ * value of the preference in the activity
+ *
+ * @param visibility A boolean value indicating whether the notification should be visible on the
+ * lockscreen
+ */
+ public void visibilityPublic(Boolean visibility) {
+ if (visibility) {
+ notBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
+ } else {
+ notBuilder.setVisibility(NotificationCompat.VISIBILITY_SECRET);
+ }
+ }
- Log.d("TrafficService", "Unknown network without SSID");
- hideNotification();
- }
- } else {
+ /**
+ * Helper method that sets the background color of the notification icon by parsing the RGB value
+ * into an int.
+ *
+ * @param color The internal int representation of the RGB color to set as the background colour
+ */
+ public void setColor(Integer color) {
+ notBuilder.setColor(color);
+ }
- Log.d("TrafficService", "Connected to a cellular network");
- if (!mgrTelephony.getNetworkOperatorName().trim().isEmpty()) {
+ /**
+ * Binder method to allow the settings activity to bind to the service so the notification can be
+ * configured and updated while the activity is being toggles.
+ *
+ * @see android.app.Service#onBind(android.content.Intent)
+ */
+ @Override
+ public IBinder onBind(Intent intReason) {
+ return mBinder;
+ }
- Log.d("TrafficService", mgrTelephony.getNetworkOperatorName());
- notBuilder.setContentTitle(getString(R.string.cellular));
- notBuilder.setContentText(mgrTelephony.getNetworkOperatorName());
- showNotification();
- } else {
+ /**
+ * The handler class that runs every second to update the notification with the network speed. It
+ * also runs every minute to save the amount of data-transferred to the preferences.
+ */
+ private static class NotificationHandler extends Handler {
- Log.d("TrafficService", "Unknown network without IMSI");
- hideNotification();
- }
- }
- } else {
+ /**
+ * The instance of the context of the parent service
+ */
+ private final Context ctxContext;
+ /**
+ * The value of the amount of data transferred in the previous invocation of the method
+ */
+ private long lngPrevious = 0L;
- Log.d("TrafficService", "Network disconnected; hiding the notification");
- hideNotification();
- }
- }
+ /**
+ * Simple constructor to initialize the initial value of the previous
+ */
+ @SuppressLint("CommitPrefEdits")
+ public NotificationHandler(Context ctxContext) {
+ this.ctxContext = ctxContext;
+ }
- /**
- Called when the service is being stopped. It doesn't do much except clear the message queue of
- the handler, hides the notification and unregisters the receivers.
- */
- @Override
- public void onDestroy() {
+ /**
+ * Handler method that updates the notification icon with the current speed. It is a very
+ * hackish method. We have icons for 1 KB/s to 999 KB/s and 1.0 MB/s to 99.9 MB/s. Every time
+ * the method is invoked, we get the amount of data transferred. By subtracting this value with
+ * the previous value, we get the delta. Since this method is invoked every second, this delta
+ * value indicates the b/s. However, we need to convert this value into KB/s for values under 1
+ * MB/s and we need to convert the value to MB/s for values over 1 MB/s. Since all our icon
+ * images are numbered sequentially we can assume that the R class generated will contain the
+ * integer references of the drawables in the sequential order.
+ */
+ @Override
+ public void handleMessage(Message msgMessage) {
- Log.d("HardwareService", "Stopping the hardware service");
- unregisterReceiver(recScreen);
- hndNotifier.removeMessages(1);
- mgrNotifications.cancel(ID);
- }
+ TrafficService.hndNotifier.sendEmptyMessageDelayed(1, 1000L);
- /**
- Helper method that shows the notification by sending the handler a message and building the
- notification. This is invoked when the preference is toggled.
- */
- public void showNotification() {
+ long lngCurrent = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();
+ int lngSpeed = (int) (lngCurrent - lngPrevious);
+ lngPrevious = lngCurrent;
- Log.d("HardwareService", "Showing the notification");
- mgrNotifications.notify(ID, notBuilder.build());
- hndNotifier.removeMessages(1);
- hndNotifier.sendEmptyMessage(1);
- }
+ try {
- /**
- Helper method that hides the notification by clearing the handler messages and cancelling the
- notification. This is invoked when the preference is toggled.
- */
- public void hideNotification() {
+ if (lngSpeed < 1024) {
+ TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000);
+ } else if (lngSpeed < 1048576L) {
- Log.d("HardwareService", "Hiding the notification");
- mgrNotifications.cancel(ID);
- hndNotifier.removeMessages(1);
- }
+ TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000 + (int) (lngSpeed / 1024L));
+ if (lngSpeed > 1022976) {
+ TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000 + 1000);
+ }
+ } else if (lngSpeed <= 10485760) {
+ TrafficService.notBuilder.setSmallIcon(990 + R.drawable.wkb000
+ + (int) (0.5D + (double) (10F * ((float) lngSpeed / 1048576F))));
+ } else if (lngSpeed <= 103809024) {
+ TrafficService.notBuilder.setSmallIcon(1080 + R.drawable.wkb000
+ + (int) (0.5D + (double) ((float) lngSpeed / 1048576F)));
+ } else {
+ TrafficService.notBuilder.setSmallIcon(1180 + R.drawable.wkb000);
+ }
- /**
- Helper method that toggles the visibility of the notification on the locksreen depending on the
- value of the preference in the activity
+ Long lngTotal = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();
+ String strTotal = Formatter.formatFileSize(this.ctxContext, lngTotal);
+ TrafficService.notBuilder.setContentInfo(strTotal);
+ TrafficService.mgrNotifications.notify(ID, TrafficService.notBuilder.build());
+ } catch (Exception e) {
+ Log.e("NotificationHandler", "Error creating notification for speed " + lngSpeed);
+ }
+ }
+ }
- @param visibility A boolean value indicating whether the notification should be visible on the
- lockscreen
- */
- public void visibilityPublic(Boolean visibility) {
- if (visibility) {
- notBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
- } else {
- notBuilder.setVisibility(NotificationCompat.VISIBILITY_SECRET);
- }
- }
+ /**
+ * Custom binder class used for allowing the preference activity to bind to this service so that it
+ * may be configured on the fly
+ */
+ public class LocalBinder extends Binder {
- /**
- Helper method that sets the background color of the notification icon by parsing the RGB value
- into an int.
-
- @param color The internal int representation of the RGB color to set as the background colour
- */
- public void setColor(Integer color) {
- notBuilder.setColor(color);
- }
-
- /**
- Binder method to allow the settings activity to bind to the service so the notification can be
- configured and updated while the activity is being toggles.
-
- @see android.app.Service#onBind(android.content.Intent)
- */
- @Override
- public IBinder onBind(Intent intReason) {
- return mBinder;
- }
+ public TrafficService getServerInstance() {
+ return TrafficService.this;
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 67b19bc..7095f82 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,8 +4,10 @@
Cellular network connectivity
Shows or hides the notification icon
Enabled
- Show the notification in the lockscreen when the phone is locked
+ Show the notification in the lockscreen when the device is locked
Publicly visible
+ Disable on low battery
+ Disable the notification and the service when the device\'s battery is low or when the power saving mode is enabled
Background color of the notification icon
Color
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 6c17014..7838931 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -10,6 +10,11 @@
android:key="lockscreen"
android:summary="@string/lockscreen_summary"
android:title="@string/lockscreen_title"/>
+
-
-
-
-
-
-
-
-
-
+