diff --git a/.gitignore b/.gitignore index c31d6c6..d6bfe50 100644 --- a/.gitignore +++ b/.gitignore @@ -29,13 +29,10 @@ proguard/ # Android Studio .gitignore default file *.iml -.gradle -/local.properties /.idea/workspace.xml /.idea/libraries /.idea/copyright .DS_Store -/build /captures # Assets folders diff --git a/.idea/modules.xml b/.idea/modules.xml index 56eda61..b88e6ff 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -3,7 +3,7 @@ - + \ No newline at end of file diff --git a/README.md b/README.md index dfb4853..7241e08 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # GreenHub BatteryHub -[![Build Status](https://travis-ci.org/hmatalonga/greenhub.svg?branch=master)](https://travis-ci.org/hmatalonga/greenhub) +[![Build Status](https://travis-ci.org/greenhub-project/batteryhub.svg?branch=master)](https://travis-ci.org/hmatalonga/greenhub) GreenHub is a collaborative approach to power consumption analysis of Android devices. diff --git a/app/src/main/java/com/hmatalonga/greenhub/Config.java b/app/src/main/java/com/hmatalonga/greenhub/Config.java index a86aecd..8348538 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/Config.java +++ b/app/src/main/java/com/hmatalonga/greenhub/Config.java @@ -52,7 +52,6 @@ public final class Config { // Whether to output debug messages. public static final boolean DEBUG = true; - public static final boolean PRODUCTION = false; public static final String SERVER_STATUS_URL = "http://greenhub.hmatalonga.com/"; public static final String SERVER_URL_DEFAULT = "none"; @@ -90,7 +89,11 @@ public final class Config { public static final int REFRESH_STATUS_BAR_INTERVAL = REFRESH_CURRENT_INTERVAL * 6; public static final int REFRESH_STATUS_ERROR = REFRESH_CURRENT_INTERVAL * 2; + public static final String NOTIFICATION_DEFAULT_TEMPERATURE_RATE = "5"; public static final double BATTERY_LOW_LEVEL = 0.2; + public static final int BATTERY_TEMPERATURE_MEDIUM = 35; + public static final int BATTERY_TEMPERATURE_HIGH = 45; + public static final String STATUS_IDLE = "Idle"; diff --git a/app/src/main/java/com/hmatalonga/greenhub/GreenHubApp.java b/app/src/main/java/com/hmatalonga/greenhub/GreenHubApp.java index f70a2d2..fd95570 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/GreenHubApp.java +++ b/app/src/main/java/com/hmatalonga/greenhub/GreenHubApp.java @@ -40,6 +40,7 @@ import io.realm.RealmMigration; import io.realm.RealmSchema; +import static com.hmatalonga.greenhub.util.LogUtils.LOGE; import static com.hmatalonga.greenhub.util.LogUtils.LOGI; import static com.hmatalonga.greenhub.util.LogUtils.makeLogTag; @@ -131,9 +132,14 @@ public void run() { } public void stopGreenHubService() { - if (estimator != null) { - unregisterReceiver(estimator); - isServiceRunning = false; + try { + if (estimator != null) { + unregisterReceiver(estimator); + isServiceRunning = false; + } + } catch (IllegalArgumentException e) { + LOGE(TAG, "Estimator receiver is not registered!"); + e.printStackTrace(); } } diff --git a/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimator.java b/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimator.java index 18524ee..517c36d 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimator.java +++ b/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimator.java @@ -20,16 +20,20 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.ReceiverCallNotAllowedException; import android.os.BatteryManager; import android.support.v4.content.WakefulBroadcastReceiver; -import android.widget.Toast; - -import org.greenrobot.eventbus.EventBus; +import com.hmatalonga.greenhub.Config; import com.hmatalonga.greenhub.events.BatteryLevelEvent; +import com.hmatalonga.greenhub.models.Battery; import com.hmatalonga.greenhub.util.Notifier; import com.hmatalonga.greenhub.util.SettingsUtils; +import org.greenrobot.eventbus.EventBus; + +import java.util.Calendar; + import static com.hmatalonga.greenhub.util.LogUtils.LOGE; import static com.hmatalonga.greenhub.util.LogUtils.LOGI; import static com.hmatalonga.greenhub.util.LogUtils.makeLogTag; @@ -86,12 +90,43 @@ public void onReceive(Context context, Intent intent) { e.printStackTrace(); } - if (SettingsUtils.isBatteryAlertsOn(context)) { - // Notify for temperature alerts... - if (temperature > 45) { - Notifier.batteryHighTemperature(context); - } else if (temperature <= 45 && temperature > 35) { - Notifier.batteryWarningTemperature(context); + // We don't send battery level alerts here because we need to check if the level changed + // So we verify that inside the DataEstimator Service + + if (temperature > Config.BATTERY_TEMPERATURE_MEDIUM) { + if (SettingsUtils.isBatteryAlertsOn(context) && + SettingsUtils.isTemperatureAlertsOn(context)) { + + // Check temperature limit rate + Calendar lastAlert = Calendar.getInstance(); + long lastSavedTime = SettingsUtils.fetchLastTemperatureAlertDate(context); + + // Set last alert time with saved preferences + if (lastSavedTime != 0) { + lastAlert.setTimeInMillis(lastSavedTime); + } + int minutes = SettingsUtils.fetchTemperatureAlertsRate(context); + + lastAlert.add(Calendar.MINUTE, minutes); + + // If last saved time isn't default and now is after limit rate then notify + if (lastSavedTime == 0 || Calendar.getInstance().after(lastAlert)) { + // Notify for temperature alerts... + if (temperature > Config.BATTERY_TEMPERATURE_HIGH) { + Notifier.batteryHighTemperature(context); + SettingsUtils.saveLastTemperatureAlertDate( + context, + System.currentTimeMillis() + ); + } else if (temperature <= Config.BATTERY_TEMPERATURE_HIGH && + temperature > Config.BATTERY_TEMPERATURE_MEDIUM) { + Notifier.batteryWarningTemperature(context); + SettingsUtils.saveLastTemperatureAlertDate( + context, + System.currentTimeMillis() + ); + } + } } } } @@ -135,18 +170,25 @@ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED) // Getters & Setters public void getCurrentStatus(final Context context) { IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); - Intent batteryStatus = context.registerReceiver(null, ifilter); - assert batteryStatus != null; - - level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); - scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); - health = batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH, 0); - plugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); - present = batteryStatus.getExtras().getBoolean(BatteryManager.EXTRA_PRESENT); - status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, 0); - technology = batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY); - temperature = (float) (batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) / 10); - voltage = (float) (batteryStatus.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) / 1000); + + try { + Intent batteryStatus = context.registerReceiver(null, ifilter); + + if (batteryStatus != null) { + level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); + scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + health = batteryStatus.getIntExtra(BatteryManager.EXTRA_HEALTH, 0); + plugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); + present = batteryStatus.getExtras().getBoolean(BatteryManager.EXTRA_PRESENT); + status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, 0); + technology = batteryStatus.getExtras().getString(BatteryManager.EXTRA_TECHNOLOGY); + temperature = (float) (batteryStatus.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0) / 10); + voltage = (float) (batteryStatus.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0) / 1000); + } + } catch (ReceiverCallNotAllowedException e) { + LOGE(TAG, "ReceiverCallNotAllowedException from Notification Receiver?"); + e.printStackTrace(); + } } public String getHealthStatus() { diff --git a/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimatorService.java b/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimatorService.java index 9e97f50..224afbd 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimatorService.java +++ b/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/DataEstimatorService.java @@ -181,7 +181,8 @@ private void takeSampleIfBatteryLevelChanged(Intent intent, final Context contex boolean isPlugged = 0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); - if (SettingsUtils.isBatteryAlertsOn(context)) { + if (SettingsUtils.isBatteryAlertsOn(context) && + SettingsUtils.isChargeAlertsOn(context)) { if (Inspector.getCurrentBatteryLevel() == 1 && isPlugged) { Notifier.batteryFullAlert(context); } else if (Inspector.getCurrentBatteryLevel() == Config.BATTERY_LOW_LEVEL) { diff --git a/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/Inspector.java b/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/Inspector.java index b45fb7d..fdd476d 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/Inspector.java +++ b/app/src/main/java/com/hmatalonga/greenhub/managers/sampling/Inspector.java @@ -59,15 +59,6 @@ import android.preference.PreferenceManager; import android.util.Log; -import org.greenrobot.eventbus.EventBus; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - import com.hmatalonga.greenhub.BuildConfig; import com.hmatalonga.greenhub.Config; import com.hmatalonga.greenhub.events.StatusEvent; @@ -99,6 +90,17 @@ import com.hmatalonga.greenhub.models.data.Sample; import com.hmatalonga.greenhub.models.data.Settings; import com.hmatalonga.greenhub.util.SettingsUtils; + +import org.greenrobot.eventbus.EventBus; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + import io.realm.RealmList; import static com.hmatalonga.greenhub.util.LogUtils.LOGI; @@ -124,6 +126,7 @@ public final class Inspector { private static double sCurrentBatteryLevel = 0; + // we might not be able to read the current battery level at the first run // of GreenHub. // so it might be zero until we get the non-zero value from the intent @@ -134,10 +137,6 @@ public final class Inspector { */ private Inspector() {} - public static double readLastBatteryLevel() { - return sLastBatteryLevel; - } - public static void setLastBatteryLevel(double level) { sLastBatteryLevel = level; } @@ -150,10 +149,6 @@ public static double getCurrentBatteryLevel() { return sCurrentBatteryLevel; } - public static void setCurrentBatteryLevel(double level) { - sCurrentBatteryLevel = level; - } - /** * Take in currentLevel and scale as doubles to avoid loss of precision issues. * Note that GreenHub stores battery level as a value between 0 and 1, e.g. 0.45 for 45%. diff --git a/app/src/main/java/com/hmatalonga/greenhub/models/Battery.java b/app/src/main/java/com/hmatalonga/greenhub/models/Battery.java index 0c1e7fe..2d3605d 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/models/Battery.java +++ b/app/src/main/java/com/hmatalonga/greenhub/models/Battery.java @@ -27,6 +27,7 @@ import java.lang.reflect.Method; import com.hmatalonga.greenhub.Config; +import com.hmatalonga.greenhub.util.SettingsUtils; import static com.hmatalonga.greenhub.util.LogUtils.LOGI; import static com.hmatalonga.greenhub.util.LogUtils.makeLogTag; @@ -146,6 +147,53 @@ public static long getBatteryEnergyCounter(final Context context) { return (value != Long.MIN_VALUE) ? value : -1; } + /** + * Calculate Average Power + * Average Power = (Average Voltage * Average Current) / 1e9 + * + * @param context Context of application + * @return Average power in integer + */ + public static int getBatteryAveragePower(final Context context) { + int voltage; + int current = 0; + + Intent receiver = + context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + + if (receiver == null) return -1; + + voltage = receiver.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + BatteryManager manager = (BatteryManager) + context.getSystemService(Context.BATTERY_SERVICE); + current = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE); + } + + return (voltage * current) / 1000000000; + } + + /** + * Calculate Battery Capacity Consumed + * Battery Capacity Consumed = (Average Current * Workload Duration) / 1e3 + * + * @param workload Workload duration (in hours) + * @param context Context of application + * @return Average power in integer + */ + public static double getBatteryCapacityConsumed(final double workload, final Context context) { + int current = 0; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + BatteryManager manager = (BatteryManager) + context.getSystemService(Context.BATTERY_SERVICE); + current = manager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE); + } + + return (current * workload) / 1000; + } + private static int getBatteryCurrentNowLegacy() { int value = -1; diff --git a/app/src/main/java/com/hmatalonga/greenhub/models/data/BatteryDetails.java b/app/src/main/java/com/hmatalonga/greenhub/models/data/BatteryDetails.java index 3ef35f7..c604a9d 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/models/data/BatteryDetails.java +++ b/app/src/main/java/com/hmatalonga/greenhub/models/data/BatteryDetails.java @@ -47,7 +47,7 @@ public class BatteryDetails extends RealmObject { // Average battery current in microAmperes public int currentAverage; - // Instantaneous battery current in microAmperes + // Instantaneous battery current in milliAmperes public int currentNow; // Battery remaining energy in nanoWatt-hours diff --git a/app/src/main/java/com/hmatalonga/greenhub/receivers/ConnectivityReceiver.java b/app/src/main/java/com/hmatalonga/greenhub/receivers/ConnectivityReceiver.java index 1b78167..0ec1337 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/receivers/ConnectivityReceiver.java +++ b/app/src/main/java/com/hmatalonga/greenhub/receivers/ConnectivityReceiver.java @@ -77,7 +77,7 @@ public void onReceive(Context context, Intent intent) { new CheckNewMessagesTask().execute(context); } - if (CommunicationManager.isQueued) { + if (CommunicationManager.isQueued && SettingsUtils.isServerUrlPresent(context)) { CommunicationManager manager = new CommunicationManager(context, true); manager.sendSamples(); CommunicationManager.isQueued = false; diff --git a/app/src/main/java/com/hmatalonga/greenhub/receivers/NotificationReceiver.java b/app/src/main/java/com/hmatalonga/greenhub/receivers/NotificationReceiver.java index d061cc5..81f06e0 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/receivers/NotificationReceiver.java +++ b/app/src/main/java/com/hmatalonga/greenhub/receivers/NotificationReceiver.java @@ -3,6 +3,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.ReceiverCallNotAllowedException; import com.hmatalonga.greenhub.util.LogUtils; import com.hmatalonga.greenhub.util.Notifier; @@ -16,6 +17,10 @@ public class NotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { LOGI(TAG, "onReceive called!"); - Notifier.updateStatusBar(context); + try { + Notifier.updateStatusBar(context); + } catch (ReceiverCallNotAllowedException e) { + e.printStackTrace(); + } } } diff --git a/app/src/main/java/com/hmatalonga/greenhub/ui/InboxActivity.java b/app/src/main/java/com/hmatalonga/greenhub/ui/InboxActivity.java index 83b9033..db45edd 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/ui/InboxActivity.java +++ b/app/src/main/java/com/hmatalonga/greenhub/ui/InboxActivity.java @@ -7,6 +7,8 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.TextView; import com.hmatalonga.greenhub.R; import com.hmatalonga.greenhub.events.OpenMessageEvent; @@ -26,6 +28,8 @@ public class InboxActivity extends BaseActivity { private RecyclerView mRecyclerView; + private TextView mNoMessagesTextView; + private MessageAdapter mAdapter; private ArrayList mMessages; @@ -43,6 +47,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { actionBar.setDisplayHomeAsUpEnabled(true); } + mNoMessagesTextView = (TextView) findViewById(R.id.no_messages_view); mRecyclerView = (RecyclerView) findViewById(R.id.rv); mAdapter = null; @@ -117,5 +122,14 @@ private void setAdapter() { mAdapter.swap(mMessages); } mRecyclerView.invalidate(); + + if (mMessages.isEmpty()) { + mRecyclerView.setVisibility(View.GONE); + mNoMessagesTextView.setVisibility(View.VISIBLE); + } + else { + mRecyclerView.setVisibility(View.VISIBLE); + mNoMessagesTextView.setVisibility(View.GONE); + } } } diff --git a/app/src/main/java/com/hmatalonga/greenhub/ui/MainActivity.java b/app/src/main/java/com/hmatalonga/greenhub/ui/MainActivity.java index 34c9f14..4a442a5 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/ui/MainActivity.java +++ b/app/src/main/java/com/hmatalonga/greenhub/ui/MainActivity.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -78,6 +79,15 @@ protected void onCreate(Bundle savedInstanceState) { LOGI(TAG, "onCreate() called"); loadComponents(); + + Intent intentFromNotifier = getIntent(); + + if (intentFromNotifier != null) { + int tab = intentFromNotifier.getIntExtra("tab", -1); + if (tab != -1) { + mViewPager.setCurrentItem(tab); + } + } } @Override @@ -110,7 +120,16 @@ public boolean onMenuItemClick(MenuItem item) { startActivity(new Intent(this, InboxActivity.class)); return true; case R.id.action_summary: - startActivity(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY)); + try { + Intent powerSummary = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY); + ResolveInfo resolveInfo = getPackageManager().resolveActivity(powerSummary, 0); + if (resolveInfo != null) { + startActivity(powerSummary); + } + // TODO: else show dialog + } catch (ActivityNotFoundException e) { + e.printStackTrace(); + } return true; case R.id.action_settings: startActivity(new Intent(this, SettingsActivity.class)); diff --git a/app/src/main/java/com/hmatalonga/greenhub/ui/SettingsActivity.java b/app/src/main/java/com/hmatalonga/greenhub/ui/SettingsActivity.java index 261eb01..18a38af 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/ui/SettingsActivity.java +++ b/app/src/main/java/com/hmatalonga/greenhub/ui/SettingsActivity.java @@ -72,6 +72,7 @@ public void onCreate(Bundle savedInstanceState) { bindPreferenceSummaryToValue(findPreference(SettingsUtils.PREF_DATA_HISTORY)); bindPreferenceSummaryToValue(findPreference(SettingsUtils.PREF_UPLOAD_RATE)); + bindPreferenceSummaryToValue(findPreference(SettingsUtils.PREF_TEMPERATURE_RATE)); bindPreferenceSummaryToValue(findPreference(SettingsUtils.PREF_NOTIFICATIONS_PRIORITY)); SettingsUtils.registerOnSharedPreferenceChangeListener(getActivity(), this); @@ -114,6 +115,9 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin app.stopStatusBarUpdater(); } break; + case SettingsUtils.PREF_TEMPERATURE_RATE: + bindPreferenceSummaryToValue(findPreference(SettingsUtils.PREF_TEMPERATURE_RATE)); + break; case SettingsUtils.PREF_NOTIFICATIONS_PRIORITY: bindPreferenceSummaryToValue(findPreference(SettingsUtils.PREF_NOTIFICATIONS_PRIORITY)); break; diff --git a/app/src/main/java/com/hmatalonga/greenhub/util/Notifier.java b/app/src/main/java/com/hmatalonga/greenhub/util/Notifier.java index 59efc90..28281af 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/util/Notifier.java +++ b/app/src/main/java/com/hmatalonga/greenhub/util/Notifier.java @@ -207,6 +207,25 @@ public static void batteryFullAlert(final Context context) { mBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); } + // Creates an explicit intent for an Activity in your app + Intent resultIntent = new Intent(context, MainActivity.class); + + // The stack builder object will contain an artificial back stack for the + // started Activity. + // This ensures that navigating backward from the Activity leads out of + // your application to the Home screen. + TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(InboxActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); + mBuilder.setContentIntent(resultPendingIntent); + // Because the ID remains unchanged, the existing notification is updated. sNotificationManager.notify(Config.NOTIFICATION_BATTERY_FULL, mBuilder.build()); } @@ -231,6 +250,25 @@ public static void batteryLowAlert(final Context context) { mBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); } + // Creates an explicit intent for an Activity in your app + Intent resultIntent = new Intent(context, MainActivity.class); + + // The stack builder object will contain an artificial back stack for the + // started Activity. + // This ensures that navigating backward from the Activity leads out of + // your application to the Home screen. + TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(InboxActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); + mBuilder.setContentIntent(resultPendingIntent); + // Because the ID remains unchanged, the existing notification is updated. sNotificationManager.notify(Config.NOTIFICATION_BATTERY_LOW, mBuilder.build()); } @@ -255,6 +293,26 @@ public static void batteryWarningTemperature(final Context context) { mBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); } + // Creates an explicit intent for an Activity in your app + Intent resultIntent = new Intent(context, MainActivity.class); + resultIntent.putExtra("tab", 2); + + // The stack builder object will contain an artificial back stack for the + // started Activity. + // This ensures that navigating backward from the Activity leads out of + // your application to the Home screen. + TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(InboxActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); + mBuilder.setContentIntent(resultPendingIntent); + // Because the ID remains unchanged, the existing notification is updated. Notification notification = mBuilder.build(); notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; @@ -281,6 +339,26 @@ public static void batteryHighTemperature(final Context context) { mBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); } + // Creates an explicit intent for an Activity in your app + Intent resultIntent = new Intent(context, MainActivity.class); + resultIntent.putExtra("tab", 2); + + // The stack builder object will contain an artificial back stack for the + // started Activity. + // This ensures that navigating backward from the Activity leads out of + // your application to the Home screen. + TaskStackBuilder stackBuilder = TaskStackBuilder.create(context); + // Adds the back stack for the Intent (but not the Intent itself) + stackBuilder.addParentStack(InboxActivity.class); + // Adds the Intent that starts the Activity to the top of the stack + stackBuilder.addNextIntent(resultIntent); + PendingIntent resultPendingIntent = + stackBuilder.getPendingIntent( + 0, + PendingIntent.FLAG_UPDATE_CURRENT + ); + mBuilder.setContentIntent(resultPendingIntent); + // Because the ID remains unchanged, the existing notification is updated. Notification notification = mBuilder.build(); notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; diff --git a/app/src/main/java/com/hmatalonga/greenhub/util/SettingsUtils.java b/app/src/main/java/com/hmatalonga/greenhub/util/SettingsUtils.java index 9330435..d1fda78 100644 --- a/app/src/main/java/com/hmatalonga/greenhub/util/SettingsUtils.java +++ b/app/src/main/java/com/hmatalonga/greenhub/util/SettingsUtils.java @@ -33,6 +33,8 @@ public class SettingsUtils { private static final String TAG = "SettingsUtils"; + // region Preferences Declarations + /** * Boolean indicating whether ToS has been accepted. */ @@ -81,6 +83,22 @@ public class SettingsUtils { * Boolean indicating whether to display battery alerts. */ public static final String PREF_BATTERY_ALERTS = "pref_battery_alerts"; + /** + * Boolean indicating whether to display battery charging/level alerts. + */ + public static final String PREF_CHARGE_ALERTS = "pref_charge_alerts"; + /** + * Boolean indicating whether to display battery temperature alerts. + */ + public static final String PREF_TEMPERATURE_ALERTS = "pref_temperature_alerts"; + /** + * Integer indicating which temperature interval rate to use. + */ + public static final String PREF_TEMPERATURE_RATE = "pref_temperature_rate"; + /** + * Long integer indicating when was send the last battery temperature alert. + */ + public static final String PREF_LAST_TEMPERATURE_ALERT = "pref_last_temperature_alert"; /** * Boolean indicating whether to display battery alerts. */ @@ -97,6 +115,12 @@ public class SettingsUtils { * Boolean indicating whether to hide system apps or not. */ public static final String PREF_HIDE_SYSTEM_APPS = "pref_system_apps"; + /** + * Boolean indicating whether to use the old measurement or not. + */ + public static final String PREF_USE_OLD_MEASUREMENT = "pref_old_measurement"; + + // endregion /** * Return true if user has accepted the @@ -251,6 +275,54 @@ public static boolean isBatteryAlertsOn(final Context context) { return sp.getBoolean(PREF_BATTERY_ALERTS, true); } + /** + * Return true if charge related alerts are to be shown, false if hidden. + * + * @param context Context to be used to lookup the {@link android.content.SharedPreferences}. + */ + public static boolean isChargeAlertsOn(final Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + return sp.getBoolean(PREF_CHARGE_ALERTS, true); + } + + /** + * Return true if temperature related alerts are to be shown, false if hidden. + * + * @param context Context to be used to lookup the {@link android.content.SharedPreferences}. + */ + public static boolean isTemperatureAlertsOn(final Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + return sp.getBoolean(PREF_TEMPERATURE_ALERTS, true); + } + + public static int fetchTemperatureAlertsRate(final Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + return Integer.parseInt( + sp.getString(PREF_TEMPERATURE_RATE, Config.NOTIFICATION_DEFAULT_TEMPERATURE_RATE) + ); + } + + /** + * Save the new last time of battery temperature alert. + * + * @param context Context to be used to edit the {@link android.content.SharedPreferences}. + * @param time New value that will be set. + */ + public static void saveLastTemperatureAlertDate(final Context context, long time) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + sp.edit().putLong(PREF_LAST_TEMPERATURE_ALERT, time).apply(); + } + + /** + * Return the time in millis of the last battery temperature alert + * + * @param context Context to be used to lookup the {@link android.content.SharedPreferences}. + */ + public static long fetchLastTemperatureAlertDate(final Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + return sp.getLong(PREF_LAST_TEMPERATURE_ALERT, 0); + } + /** * Return true if message alerts are to be shown, false if hidden. * @@ -303,6 +375,26 @@ public static void markSystemAppsHidden(final Context context, boolean newValue) sp.edit().putBoolean(PREF_HIDE_SYSTEM_APPS, newValue).apply(); } + /** + * Return true if old measurement method is being used, false if it isn't. + * + * @param context Context to be used to lookup the {@link android.content.SharedPreferences}. + */ + public static boolean isOldMeasurementUsed(final Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + return sp.getBoolean(PREF_USE_OLD_MEASUREMENT, false); + } + /** + * Mark {@code newValue whether} old measurement method to be used. + * + * @param context Context to be used to edit the {@link android.content.SharedPreferences}. + * @param newValue New value that will be set. + */ + public static void markOldMeasurementUsed(final Context context, boolean newValue) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + sp.edit().putBoolean(PREF_USE_OLD_MEASUREMENT, newValue).apply(); + } + /** * Save the most recent app version {@code version}. * @@ -324,6 +416,8 @@ public static int fetchAppVersion(final Context context) { return sp.getInt(PREF_APP_VERSION, BuildConfig.VERSION_CODE); } + // region Listeners + /** * Helper method to register a settings_prefs listener. This method does not automatically handle * {@code unregisterOnSharedPreferenceChangeListener() un-registering} the listener at the end @@ -350,4 +444,6 @@ public static void unregisterOnSharedPreferenceChangeListener(final Context cont SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); sp.unregisterOnSharedPreferenceChangeListener(listener); } + + // endregion } diff --git a/app/src/main/res/layout/activity_inbox.xml b/app/src/main/res/layout/activity_inbox.xml index 009a4ea..f167c0b 100644 --- a/app/src/main/res/layout/activity_inbox.xml +++ b/app/src/main/res/layout/activity_inbox.xml @@ -26,7 +26,15 @@ android:layout_width="match_parent" android:id="@+id/rv"> - + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index a4ae22b..40667b3 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -15,16 +15,43 @@ ~ limitations under the License. --> - + + "Last 5 days" + "Last 10 days" + "Last 15 days" + + + 3 + 4 + 5 + + + "Low" "Normal" "High" - + 50 20 10 + + + "2 minutes" + "5 minutes" + "10 minutes" + "20 minutes" + "30 minutes" + + + 2 + 5 + 10 + 20 + 30 + + "Minimum" "Low" @@ -39,14 +66,4 @@ 1 2 - - "Last 5 days" - "Last 10 days" - "Last 15 days" - - - 3 - 4 - 5 - \ 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 d918bcf..e600058 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -50,6 +50,8 @@ No Internet connectivity. + There are no messages at the moment + Delete message Are you sure that you want to delete this message permanently? @@ -112,6 +114,8 @@ Track screen events Save data on screen on/off + Use old measurement method + Try this, if current now value is 0 all the time Data history @@ -120,13 +124,21 @@ Use mobile data Upload with cellular data - Uploading rate + Uploading rate Power indicator Battery alerts Show charging and temperature alerts + Charging/Discharging alerts + Show battery charge related alerts + + Temperature alerts + Show battery temperature alerts + + Temperature alerts rate + New message alerts Show incoming messages notifications diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index d6ccc85..907d5d4 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -51,10 +51,9 @@ @@ -74,6 +73,28 @@ android:title="@string/pref_title_battery_alerts" android:summary="@string/pref_description_battery_alerts"/> + + + + + +