diff --git a/app/build.gradle b/app/build.gradle
index 6818f34..c3f3c01 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,8 +1,9 @@
apply plugin: 'com.android.application'
+apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
- buildToolsVersion "23.0.1"
+ buildToolsVersion "23.0.2"
defaultConfig {
applicationId "net.kacpak.batterychargingmonitor"
@@ -13,26 +14,42 @@ android {
}
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
+ shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
+ debug {
+ debuggable true
+ minifyEnabled true
+ applicationIdSuffix ".debug"
+ versionNameSuffix '.debug'
+ }
}
}
-def supportLibrary = "23.1.1"
+repositories {
+ maven { url "https://jitpack.io" } // To compile from GitHub when MavenCentral is outdated (circleprogress)
+}
+
+ext {
+ supportLibrary_version = "23.3.0"
+ circleProgress_version = "a947edf" // TODO change to new release when startingPoint is merged
+ butterKnife_version = "8.0.1"
+}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
-
// Support Libraries
- compile "com.android.support:appcompat-v7:$supportLibrary"
- compile "com.android.support:design:$supportLibrary"
- compile "com.android.support:support-annotations:$supportLibrary"
-
+ compile "com.android.support:appcompat-v7:$supportLibrary_version"
+ compile "com.android.support:design:$supportLibrary_version"
+ compile "com.android.support:support-annotations:$supportLibrary_version"
+ compile "com.android.support:cardview-v7:$supportLibrary_version"
+ compile "com.android.support:gridlayout-v7:$supportLibrary_version"
+ compile "com.android.support:recyclerview-v7:$supportLibrary_version"
// Circle Progress
- compile 'com.github.lzyzsd:circleprogress:1.1.0@aar'
-
+ compile "com.github.lzyzsd:circleprogress:$circleProgress_version"
// Butter Knife
- compile 'com.jakewharton:butterknife:7.0.1'
+ compile "com.jakewharton:butterknife:$butterKnife_version"
+ apt "com.jakewharton:butterknife-compiler:$butterKnife_version"
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fb1eace..eb50468 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,12 +2,16 @@
+
+
+
+ android:theme="@style/AppTheme">
@@ -17,6 +21,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/App.java b/app/src/main/java/net/kacpak/batterychargingmonitor/App.java
new file mode 100644
index 0000000..39704b4
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/App.java
@@ -0,0 +1,19 @@
+package net.kacpak.batterychargingmonitor;
+
+import android.app.Application;
+import android.content.Context;
+
+public class App extends Application {
+
+ private static Context mContext;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mContext = this;
+ }
+
+ public static Context getContext(){
+ return mContext;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryDataRepository.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryDataRepository.java
index 18793d2..f75f724 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryDataRepository.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryDataRepository.java
@@ -1,9 +1,232 @@
package net.kacpak.batterychargingmonitor.data;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
+import android.preference.PreferenceManager;
+
+import net.kacpak.batterychargingmonitor.R;
+import net.kacpak.batterychargingmonitor.data.database.ChargeInformation;
+import net.kacpak.batterychargingmonitor.data.database.DatabaseContract.DataEntry;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Zarządzanie danymi o baterii i historii ładowania
+ */
public class BatteryDataRepository {
- static int p = 0;
+ private final Context mContext;
+
+ /**
+ * Tworzy nowy obiekt do zarządzania danymi o baterii i historii ładowania
+ * @param context {@see Context} aplikacji
+ */
+ public BatteryDataRepository(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Obecny stan baterii
+ */
public BatteryStatus getStatus() {
- return new BatteryStatus(++p);
+ return new BatteryStatus();
+ }
+
+ /**
+ * Zwraca stan ładowania baterii
+ * @param chargeId id z historii ładowania baterii
+ * @return stan ładowania baterii
+ */
+ public ChargeInformation getChargeInformation(long chargeId) {
+ Uri dataUri = DataEntry.buildUri(chargeId);
+ Cursor entryInfo = mContext.getContentResolver().query(
+ dataUri,
+ null,
+ null,
+ null,
+ null
+ );
+
+ if (null == entryInfo)
+ return null;
+
+ entryInfo.moveToFirst();
+ return new ChargeInformation(entryInfo);
+ }
+
+ /**
+ * Dodaje nowy wpis do historii ładowania
+ * @param start Data i godzina rozpoczęcia ładowania
+ * @param type Typ ładowarki
+ * @param percentage Początkowy procent naładowania baterii
+ * @param temperatureCelsius Temperatura w Celsjuszach
+ * @param voltage Początkowe napięcie na baterii
+ */
+ public Uri add(Date start, int type, int percentage, float temperatureCelsius, int voltage) {
+ ContentValues values = new ContentValues();
+ values.put(DataEntry.COLUMN_TYPE, type);
+ values.put(DataEntry.COLUMN_START, start.getTime());
+ values.put(DataEntry.COLUMN_START_PERCENTAGE, percentage);
+ values.put(DataEntry.COLUMN_START_TEMPERATURE_C, temperatureCelsius);
+ values.put(DataEntry.COLUMN_START_VOLTAGE, voltage);
+
+ return mContext.getContentResolver().insert(
+ DataEntry.CONTENT_URI,
+ values
+ );
+ }
+
+ /**
+ * Zakańcza ładowanie baterii
+ * @param stop Data i godzina zakończenia ładowania
+ * @param percentage Końcowy procent naładowania baterii
+ * @param temperatureCelsius Temperatura w Celsjuszach
+ * @param voltage Ostateczne napięcie na baterii
+ * @param note Notatka do ładowania
+ */
+ public int finishCharging(Date stop, int percentage, float temperatureCelsius, int voltage, String note) {
+ ContentValues values = new ContentValues();
+ values.put(DataEntry.COLUMN_CHARGE_FINISHED, 1);
+ values.put(DataEntry.COLUMN_STOP, stop.getTime());
+ values.put(DataEntry.COLUMN_STOP_PERCENTAGE, percentage);
+ values.put(DataEntry.COLUMN_STOP_TEMPERATURE_C, temperatureCelsius);
+ values.put(DataEntry.COLUMN_STOP_VOLTAGE, voltage);
+ values.put(DataEntry.COLUMN_NOTE, note);
+
+ return mContext.getContentResolver().update(
+ DataEntry.CONTENT_URI_UNFINISHED,
+ values,
+ null,
+ null
+ );
+ }
+
+ /**
+ * Usuwa z historii podane wpisy
+ * @param ids ID wpisów w bazie danych
+ */
+ public int delete(List ids) {
+ String inClause = ids.toString().replace("[", "(").replace("]", ")");
+
+ return mContext.getContentResolver().delete(
+ DataEntry.CONTENT_URI,
+ DataEntry._ID + " IN " + inClause,
+ null
+ );
+ }
+
+ /**
+ * Usuwa nic nie wnoszące wpisy z historii (krótsze niż podane w preferencjach)
+ */
+ public int deleteIrrelevant() {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+ int minDuration = 0;
+ try {
+ String irrelevantDurationPreference = prefs.getString(mContext.getString(R.string.pref_key_irrelevant_duration), "0");
+ minDuration = Integer.parseInt(irrelevantDurationPreference) * 1000;
+ } catch (Exception e) {
+ // Do nothing
+ }
+
+ return mContext.getContentResolver().delete(
+ DataEntry.CONTENT_URI,
+ "CAST(ABS(" + DataEntry.COLUMN_STOP + " - " + DataEntry.COLUMN_START + ") AS INTEGER) <= " + minDuration,
+ null
+ );
+ }
+
+ /**
+ * Łączy podane wpisy w jeden
+ * @param ids ID wpisów w bazie danych
+ */
+ public int merge(List ids) {
+ // Będziemy szukać tylko wpisów z id "(a, b, ...)"
+ String inClause = ids.toString().replace("[", "(").replace("]", ")");
+
+ Cursor entries = mContext.getContentResolver().query(
+ DataEntry.CONTENT_URI,
+ null,
+ DataEntry._ID + " IN " + inClause,
+ null,
+ DataEntry.COLUMN_START + " ASC"
+ );
+
+ // Ustalam typ wpisu dla łączenia
+ entries.moveToFirst();
+ final int typeColumnIndex = entries.getColumnIndex(DataEntry.COLUMN_TYPE);
+ int type = entries.getInt(typeColumnIndex);
+ while (entries.moveToNext()) {
+ if (entries.getInt(typeColumnIndex) != type) {
+ type = 0;
+ break;
+ }
+ }
+
+ // Wartości do wpisania
+ ContentValues values = new ContentValues();
+
+ // Sczytujemy część początkową
+ entries.moveToFirst();
+ values.put(DataEntry.COLUMN_START, entries.getLong(entries.getColumnIndex(DataEntry.COLUMN_START)));
+ values.put(DataEntry.COLUMN_START_PERCENTAGE, entries.getInt(entries.getColumnIndex(DataEntry.COLUMN_START_PERCENTAGE)));
+ values.put(DataEntry.COLUMN_START_TEMPERATURE_C, entries.getFloat(entries.getColumnIndex(DataEntry.COLUMN_START_TEMPERATURE_C)));
+ values.put(DataEntry.COLUMN_START_VOLTAGE, entries.getInt(entries.getColumnIndex(DataEntry.COLUMN_START_VOLTAGE)));
+ values.put(DataEntry.COLUMN_TYPE, type);
+
+ // Sczytujemy wartość końcową
+ entries.moveToLast();
+ values.put(DataEntry.COLUMN_STOP, entries.getLong(entries.getColumnIndex(DataEntry.COLUMN_STOP)));
+ values.put(DataEntry.COLUMN_STOP_PERCENTAGE, entries.getInt(entries.getColumnIndex(DataEntry.COLUMN_STOP_PERCENTAGE)));
+ values.put(DataEntry.COLUMN_STOP_TEMPERATURE_C, entries.getFloat(entries.getColumnIndex(DataEntry.COLUMN_STOP_TEMPERATURE_C)));
+ values.put(DataEntry.COLUMN_STOP_VOLTAGE, entries.getInt(entries.getColumnIndex(DataEntry.COLUMN_STOP_VOLTAGE)));
+
+ if (entries.getInt(entries.getColumnIndex(DataEntry.COLUMN_CHARGE_FINISHED)) == 1)
+ values.put(DataEntry.COLUMN_CHARGE_FINISHED, 1);
+
+ entries.close();
+
+
+ mContext.getContentResolver().insert(
+ DataEntry.CONTENT_URI,
+ values
+ );
+
+ return delete(ids);
+ }
+
+ /**
+ * Ilość ładowań z uwzględnieniem preferencji
+ */
+ public int getChargedCount() {
+ return getChargedCount(true);
+ }
+
+ /**
+ * Ilość ładowań
+ * @param withPreferences true dla uwzględnienia danych od użytkownika
+ */
+ public int getChargedCount(boolean withPreferences) {
+ Cursor countCursor = mContext.getContentResolver().query(
+ DataEntry.CONTENT_URI,
+ new String[] {"count(*) AS count"},
+ null,
+ null,
+ null
+ );
+
+ int count = countCursor.moveToFirst() ? countCursor.getInt(0) : 0;
+ countCursor.close();
+
+ // Jeśli nie uwzględniamy preferencji, zwróć wartość
+ if (!withPreferences)
+ return count;
+
+ // Jeśli je uwzględniamy dodaj je do wyniku
+ return count + new UserPreferences(mContext).getPreviousChargesCount();
}
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryStatus.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryStatus.java
index 4c42fdb..1b94b3d 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryStatus.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/BatteryStatus.java
@@ -1,13 +1,259 @@
package net.kacpak.batterychargingmonitor.data;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+import net.kacpak.batterychargingmonitor.App;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Aktualny status baterii
+ */
public class BatteryStatus {
- private final int percentage;
- public BatteryStatus(int percentage) {
- this.percentage = percentage;
+ /**
+ * Battery Status Changed Intent
+ */
+ private Intent mBatteryStatus;
+
+ /**
+ * Obecne natężenie prądu
+ */
+ private int mCurrent;
+
+ /**
+ * Średnie natężenie prądu
+ */
+ private int mCurrentAvg;
+
+ /**
+ * Ścieżka do folderu systemowego zawierającego dane o stanie baterii
+ */
+ private static final String mBatteryDataPath = "/sys/class/power_supply/battery/";
+
+ /**
+ * Tworzy obiekt do odczytu stanu baterii
+ */
+ public BatteryStatus() {
+ IntentFilter mFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ mBatteryStatus = App.getContext().registerReceiver(null, mFilter);
+ mCurrent = readBatteryStatus("current_now");
+ mCurrentAvg = readBatteryStatus("current_avg");
+ }
+
+ /**
+ * Zwraca zadaną wartość z obecnego stanu baterii lub {@see defaultValue}
+ * @param name wybrana stała z {@see BatteryManager}
+ */
+ private int getBatteryStatusExtra(String name) {
+ return getBatteryStatusExtra(name, -1);
+ }
+
+ /**
+ * Zwraca zadaną wartość z obecnego stanu baterii lub {@see defaultValue}
+ * @param name wybrana stała z {@see BatteryManager}
+ * @param defaultValue wartoć domyślna
+ */
+ private int getBatteryStatusExtra(String name, int defaultValue) {
+ return mBatteryStatus.getIntExtra(name, defaultValue);
+ }
+
+ /**
+ * Procent naładowania baterii
+ */
+ public int getChargePercentage() {
+ int level = getBatteryStatusExtra(BatteryManager.EXTRA_LEVEL);
+ int scale = getBatteryStatusExtra(BatteryManager.EXTRA_SCALE);
+ return (int)(100 * level / (float)scale);
+ }
+
+ /**
+ * Zwraca true jeśli telefon jest w trakcie ładowania lub ukończył ładowanie
+ */
+ public boolean isCharging() {
+ int status = getBatteryStatusExtra(BatteryManager.EXTRA_STATUS);
+ return status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL;
+ }
+
+ /**
+ * Zwraca stałą BATTERY_PLUGGED z {@see BatteryManager}
+ * @return 1: BATTERY_PLUGGED_AC, 2: BATTERY_PLUGGED_USB, 3: BATTERY_PLUGGED_WIRELESS
+ */
+ public int getPluggedInformation() {
+ return getBatteryStatusExtra(BatteryManager.EXTRA_PLUGGED);
+ }
+
+ /**
+ * Czy bateria jest ładowana z portu USB
+ */
+ public boolean isPluggedUSB() {
+ return getPluggedInformation() == BatteryManager.BATTERY_PLUGGED_USB;
+ }
+
+ /**
+ * Czy bateria ładowana jest ładowarką przewodową
+ */
+ public boolean isPluggedAC() {
+ return getPluggedInformation() == BatteryManager.BATTERY_PLUGGED_AC;
+ }
+
+ /**
+ * Czy bateria ładowana jest bezprzewodowo
+ */
+ public boolean isPluggedWireless() {
+ return getPluggedInformation() == BatteryManager.BATTERY_PLUGGED_WIRELESS;
+ }
+
+ /**
+ * Zwraca stałą BATTERY_HEALTH z {@see BatteryManager}
+ * @return 1: UNKNOWN, 2: GOOD, 3: OVERHEAT, 4: DEAD, 5: OVER_VOLTAGE, 6: UNSPECIFIED_FAILURE, 7: COLD
+ */
+ public int getHealthInformation() {
+ return getBatteryStatusExtra(BatteryManager.EXTRA_HEALTH);
+ }
+
+ /**
+ * Czy stan baterii nieokreślony
+ */
+ public boolean isHealthUnknown() {
+ return getHealthInformation() == 1;
+ }
+
+ /**
+ * Czy stan baterii dobry
+ */
+ public boolean isHealthGood() {
+ return getHealthInformation() == 2;
+ }
+
+ /**
+ * Czy bateria się przegrzewa
+ */
+ public boolean isHealthOverheat() {
+ return getHealthInformation() == 3;
+ }
+
+ /**
+ * Czy bateria zużyta
+ */
+ public boolean isHealthDead() {
+ return getHealthInformation() == 4;
+ }
+
+ /**
+ * Czy bateria ładowana zbyt wysokim prądem
+ */
+ public boolean isHealthOverVoltage() {
+ return getHealthInformation() == 5;
+ }
+
+ /**
+ * Czy bateria uległa niezidentyfikowanemu uszkodzeniu
+ */
+ public boolean isHealthUnspecifiedFailure() {
+ return getHealthInformation() == 6;
+ }
+
+ /**
+ * Czy bateria pracuje przy zbyt niskiej temperaturze
+ */
+ public boolean isHealthCold() {
+ return getHealthInformation() == 7;
+ }
+
+ /**
+ * Temperatura baterii w stopniach Celsjusza
+ */
+ public float getTemperatureInCelsius() {
+ return getBatteryStatusExtra(BatteryManager.EXTRA_TEMPERATURE) / (float)10;
+ }
+
+ /**
+ * Temperatura baterii w stopniach Fahrenheit'a
+ */
+ public float getTemperatureInFahrenheit() {
+ return getTemperatureInCelsius() * 9 / 5 + 32;
+ }
+
+ /**
+ * Napięcie baterii w mV
+ */
+ public int getVoltage() {
+ return getBatteryStatusExtra(BatteryManager.EXTRA_VOLTAGE);
+ }
+
+ /**
+ * Natężenie prądu w mA
+ */
+ public int getCurrent() {
+ return mCurrent;
+ }
+
+ /**
+ * Informuje czy dane o obecnym natężeniu prądu są dostępne
+ */
+ public boolean isCurrentAvailable() {
+ return isBatteryStatusAvailable("current_now");
+ }
+
+ /**
+ * Średnie natężenie prądu w mA
+ */
+ public int getCurrentAverage() {
+ return mCurrentAvg;
+ }
+
+ /**
+ * Informuje czy dane o średnim natężeniu prądu są dostępne
+ */
+ public boolean isCurrentAverageAvailable() {
+ return isBatteryStatusAvailable("current_avg");
+ }
+
+ /**
+ * Zwraca wartość z danego pliku lub 0
+ * @param filename
+ */
+ private int readBatteryStatus(@NonNull String filename) {
+ File file = new File(mBatteryDataPath + filename);
+
+ if (file.exists()) {
+ BufferedReader reader = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String line = reader.readLine();
+ reader.close();
+
+ return Integer.parseInt(line) / 1000;
+
+ } catch (Exception e) {
+ Log.e("Read file: " + filename, e.toString());
+
+ } finally {
+ try {
+ if (reader != null) reader.close();
+ } catch (IOException e) {
+ Log.e("Close file: " + filename, e.toString());
+ }
+ }
+ }
+
+ return 0;
}
- public int getPercentage() {
- return percentage;
+ /**
+ * Sprawdza czy dany stan baterii jest przechowywany w plikach systemowych
+ * @param filename nazwa pliku
+ */
+ private boolean isBatteryStatusAvailable(@NonNull String filename) {
+ File file = new File(mBatteryDataPath + filename);
+ return file.exists();
}
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/UserPreferences.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/UserPreferences.java
new file mode 100644
index 0000000..2e239fd
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/UserPreferences.java
@@ -0,0 +1,64 @@
+package net.kacpak.batterychargingmonitor.data;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import net.kacpak.batterychargingmonitor.R;
+
+public class UserPreferences {
+
+ private final Context mContext;
+ private final SharedPreferences mPreferences;
+
+ public UserPreferences(Context context) {
+ mContext = context;
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ }
+
+ /**
+ * Czy temperatura baterii powinna być wyświetlana w stopniach Celsjusza
+ */
+ public boolean isTemperatureInCelsius() {
+ try {
+ return mPreferences.getBoolean(
+ mContext.getString(R.string.pref_key_temperature_celsius),
+ Boolean.parseBoolean(mContext.getString(R.string.pref_key_temperature_celsius_default))
+ );
+
+ } catch (Exception e) {
+ return true;
+ }
+ }
+
+ /**
+ * Ilość podanych ładowań baterii przed instalacją aplikacji
+ */
+ public int getPreviousChargesCount() {
+ try {
+ return Integer.parseInt(
+ mPreferences.getString(
+ mContext.getString(R.string.pref_key_add_to_count),
+ mContext.getString(R.string.pref_key_add_to_count_default)
+ ));
+
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ /**
+ * Zwraca minimalny czas w sekundach, po którym wpisy nie będą automatycznie usuwane
+ */
+ public int getIrrelevantChargeDuration() {
+ try {
+ return Integer.parseInt(mPreferences.getString(
+ mContext.getString(R.string.pref_key_irrelevant_duration),
+ mContext.getString(R.string.pref_key_irrelevant_duration_default)
+ ));
+
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/ChargeInformation.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/ChargeInformation.java
new file mode 100644
index 0000000..a42b59c
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/ChargeInformation.java
@@ -0,0 +1,114 @@
+package net.kacpak.batterychargingmonitor.data.database;
+
+import android.database.Cursor;
+
+import java.util.Date;
+
+import net.kacpak.batterychargingmonitor.data.database.DatabaseContract.DataEntry;
+
+public class ChargeInformation {
+
+ private int mType;
+ private boolean mChargeFinished;
+ private long mStart;
+ private float mStartTemperature;
+ private int mStartPercentage;
+ private int mStartVoltage;
+ private long mStop;
+ private float mStopTemperature;
+ private int mStopPercentage;
+ private int mStopVoltage;
+ private String mNote;
+
+ public ChargeInformation(Cursor cursor) {
+ String[] columns = cursor.getColumnNames();
+
+ for (int i = 0; i < columns.length; i++)
+ switch (columns[i]) {
+ case DataEntry.COLUMN_TYPE:
+ mType = cursor.getInt(i);
+ break;
+ case DataEntry.COLUMN_START:
+ mStart = cursor.getLong(i);
+ break;
+ case DataEntry.COLUMN_START_TEMPERATURE_C:
+ mStartTemperature = cursor.getFloat(i);
+ break;
+ case DataEntry.COLUMN_START_PERCENTAGE:
+ mStartPercentage = cursor.getInt(i);
+ break;
+ case DataEntry.COLUMN_START_VOLTAGE:
+ mStartVoltage = cursor.getInt(i);
+ break;
+ case DataEntry.COLUMN_STOP:
+ mStop = cursor.getLong(i);
+ break;
+ case DataEntry.COLUMN_STOP_TEMPERATURE_C:
+ mStopTemperature = cursor.getFloat(i);
+ break;
+ case DataEntry.COLUMN_STOP_PERCENTAGE:
+ mStopPercentage = cursor.getInt(i);
+ break;
+ case DataEntry.COLUMN_STOP_VOLTAGE:
+ mStopVoltage = cursor.getInt(i);
+ break;
+ case DataEntry.COLUMN_NOTE:
+ mNote = cursor.getString(i);
+ break;
+ case DataEntry.COLUMN_CHARGE_FINISHED:
+ mChargeFinished = cursor.getInt(i) != 0;
+ break;
+ }
+ }
+
+ public boolean isFinished() {
+ return mChargeFinished;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public String getNote() {
+ return mNote;
+ }
+
+ public Date getStartDate() {
+ return new Date(mStart);
+ }
+
+ public float getStartTemperature() {
+ return mStartTemperature;
+ }
+
+ public int getStartPercentage() {
+ return mStartPercentage;
+ }
+
+ public int getStartVoltage() {
+ return mStartVoltage;
+ }
+
+ public Date getStopDate() {
+ return new Date(mStop);
+ }
+
+ public float getStopTemperature() {
+ return mStopTemperature;
+ }
+
+ public int getStopPercentage() {
+ return mStopPercentage;
+ }
+
+ public int getStopVoltage() {
+ return mStopVoltage;
+ }
+
+ public long getDuration() {
+ if (mStop != 0)
+ return mStop - mStart;
+ return new Date().getTime() - new Date(mStart).getTime();
+ }
+
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DataProvider.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DataProvider.java
new file mode 100644
index 0000000..8ff7025
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DataProvider.java
@@ -0,0 +1,238 @@
+package net.kacpak.batterychargingmonitor.data.database;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import net.kacpak.batterychargingmonitor.data.database.DatabaseContract;
+import net.kacpak.batterychargingmonitor.data.database.DatabaseContract.DataEntry;
+import net.kacpak.batterychargingmonitor.data.database.DatabaseHelper;
+
+import java.util.ArrayList;
+
+public class DataProvider extends ContentProvider {
+
+ private SQLiteOpenHelper mDatabase;
+
+ private static final UriMatcher sUriMatcher = buildUriMatcher();
+ private static final int DATA = 100;
+ private static final int DATA_ID = 101;
+ private static final int DATA_UNFINISHED = 102;
+
+ private static UriMatcher buildUriMatcher() {
+ final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
+ final String authority = DatabaseContract.CONTENT_AUTHORITY;
+
+ matcher.addURI(authority, DatabaseContract.DATA_PATH, DATA);
+ matcher.addURI(authority, DatabaseContract.DATA_PATH + "/#", DATA_ID);
+ matcher.addURI(authority, DatabaseContract.DATA_PATH_UNFINISHED, DATA_UNFINISHED);
+
+ return matcher;
+ }
+
+ @Override
+ public boolean onCreate() {
+ mDatabase = new DatabaseHelper(getContext());
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(@NonNull Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ Cursor returnCursor;
+
+ switch (sUriMatcher.match(uri)) {
+ case DATA: {
+ returnCursor = mDatabase.getReadableDatabase().query(
+ DataEntry.TABLE_NAME,
+ projection,
+ selection,
+ selectionArgs,
+ null,
+ null,
+ sortOrder
+ );
+ break;
+ }
+ case DATA_ID: {
+ long id = DataEntry.getIdFromUri(uri);
+ returnCursor = mDatabase.getReadableDatabase().query(
+ DataEntry.TABLE_NAME,
+ projection,
+ DataEntry._ID + " = " + id,
+ null,
+ null,
+ null,
+ sortOrder
+ );
+ break;
+ }
+ case DATA_UNFINISHED: {
+ returnCursor = mDatabase.getReadableDatabase().query(
+ DataEntry.TABLE_NAME,
+ projection,
+ DataEntry.COLUMN_CHARGE_FINISHED + " = 0",
+ null,
+ null,
+ null,
+ null
+ );
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+
+ try {
+ returnCursor.setNotificationUri(getContext().getContentResolver(), uri);
+
+ } catch (NullPointerException e) {
+ Log.e("No content resolver", e.toString());
+ }
+
+ return returnCursor;
+ }
+
+ @Nullable
+ @Override
+ public String getType(@NonNull Uri uri) {
+ final int match = sUriMatcher.match(uri);
+
+ switch (match) {
+ case DATA:
+ return DataEntry.CONTENT_TYPE;
+ case DATA_ID:
+ return DataEntry.CONTENT_ITEM_TYPE;
+ case DATA_UNFINISHED:
+ return DataEntry.CONTENT_ITEM_TYPE;
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(@NonNull Uri uri, ContentValues values) {
+ final SQLiteDatabase db = mDatabase.getWritableDatabase();
+ final int match = sUriMatcher.match(uri);
+ Uri returnUri;
+
+ switch (match) {
+ case DATA: {
+ long id = db.insert(DataEntry.TABLE_NAME, null, values);
+ if (id > 0)
+ returnUri = DataEntry.buildUri(id);
+ else
+ throw new android.database.SQLException("Failed to insert row into " + uri);
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+
+ try {
+ getContext().getContentResolver().notifyChange(uri, null);
+
+ } catch (NullPointerException e) {
+ Log.e("No content resolver", e.toString());
+ }
+
+ return returnUri;
+ }
+
+ @Override
+ public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
+ final SQLiteDatabase db = mDatabase.getWritableDatabase();
+ final int match = sUriMatcher.match(uri);
+ int rowsDeleted;
+
+ switch (match) {
+ case DATA: {
+ rowsDeleted = db.delete(DataEntry.TABLE_NAME, selection, selectionArgs);
+ break;
+ }
+ case DATA_ID: {
+ long id = DataEntry.getIdFromUri(uri);
+ rowsDeleted = db.delete(DataEntry.TABLE_NAME, DataEntry._ID + " = " + id, null);
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+
+ try {
+ if (rowsDeleted != 0)
+ getContext().getContentResolver().notifyChange(uri, null);
+
+ } catch (NullPointerException e) {
+ Log.e("No content resolver", e.toString());
+ }
+
+ return rowsDeleted;
+ }
+
+ @Override
+ public int update(@NonNull Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ final SQLiteDatabase db = mDatabase.getWritableDatabase();
+ final int match = sUriMatcher.match(uri);
+ int rowsUpdated;
+
+ switch (match) {
+ case DATA: {
+ rowsUpdated = db.update(DataEntry.TABLE_NAME, values, selection, selectionArgs);
+ break;
+ }
+ case DATA_UNFINISHED: {
+ Cursor cursor = query(
+ DataEntry.CONTENT_URI_UNFINISHED,
+ new String[] { DataEntry._ID },
+ null,
+ null,
+ null
+ );
+
+ ArrayList ids = new ArrayList<>();
+ while (cursor.moveToNext())
+ ids.add(cursor.getLong(0));
+ cursor.close();
+ String inClause = ids.toString().replace("[", "(").replace("]", ")");
+
+ rowsUpdated = db.update(
+ DataEntry.TABLE_NAME,
+ values,
+ DataEntry._ID + " IN " + inClause,
+ null
+ );
+ break;
+ }
+ case DATA_ID: {
+ rowsUpdated = db.update(
+ DataEntry.TABLE_NAME,
+ values,
+ DataEntry._ID + " = " + DataEntry.getIdFromUri(uri),
+ null
+ );
+ break;
+ }
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+
+ try {
+ if (rowsUpdated != 0)
+ getContext().getContentResolver().notifyChange(uri, null);
+
+ } catch (NullPointerException e) {
+ Log.e("No content resolver", e.toString());
+ }
+
+ return rowsUpdated;
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DatabaseContract.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DatabaseContract.java
new file mode 100644
index 0000000..ed0b5ef
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DatabaseContract.java
@@ -0,0 +1,51 @@
+package net.kacpak.batterychargingmonitor.data.database;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+public final class DatabaseContract {
+
+ public static final String CONTENT_AUTHORITY = "net.kacpak.batterychargingmonitor";
+ public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
+
+ public static final String DATA_PATH = DataEntry.TABLE_NAME;
+ public static final String DATA_PATH_UNFINISHED = DATA_PATH + "/" + DataEntry.PATH_UNFINISHED;
+
+ public static final class DataEntry implements BaseColumns {
+ public static final String TABLE_NAME = "batteryHistory";
+ public static final String COLUMN_NOTE = "note";
+ public static final String COLUMN_TYPE = "type";
+ public static final String COLUMN_START = "start";
+ public static final String COLUMN_START_PERCENTAGE = "start_percentage";
+ public static final String COLUMN_START_VOLTAGE = "start_voltage";
+ public static final String COLUMN_START_TEMPERATURE_C = "start_temperature_c";
+ public static final String COLUMN_STOP = "stop";
+ public static final String COLUMN_STOP_PERCENTAGE = "stop_percentage";
+ public static final String COLUMN_STOP_VOLTAGE = "stop_voltage";
+ public static final String COLUMN_STOP_TEMPERATURE_C = "stop_temperature_c";
+ public static final String COLUMN_CHARGE_FINISHED = "charge_finished";
+ public static final String PATH_UNFINISHED = "unfinished";
+
+ public static final Uri CONTENT_URI =
+ BASE_CONTENT_URI.buildUpon().appendPath(DATA_PATH).build();
+
+ public static final Uri CONTENT_URI_UNFINISHED =
+ CONTENT_URI.buildUpon().appendPath(PATH_UNFINISHED).build();
+
+ public static final String CONTENT_TYPE =
+ ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + DATA_PATH;
+
+ public static final String CONTENT_ITEM_TYPE =
+ ContentResolver.CURSOR_ITEM_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + DATA_PATH;
+
+ public static Uri buildUri(long id) {
+ return ContentUris.withAppendedId(CONTENT_URI, id);
+ }
+
+ public static long getIdFromUri(Uri uri) {
+ return Long.parseLong(uri.getPathSegments().get(1));
+ }
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DatabaseHelper.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DatabaseHelper.java
new file mode 100644
index 0000000..24c9ec5
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/database/DatabaseHelper.java
@@ -0,0 +1,42 @@
+package net.kacpak.batterychargingmonitor.data.database;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import net.kacpak.batterychargingmonitor.data.database.DatabaseContract.DataEntry;
+
+public class DatabaseHelper extends SQLiteOpenHelper {
+
+ private static final int DATABASE_VERSION = 1;
+ public static final String DATABASE_NAME = "battery_history.db";
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ final String SQL_CREATE_DATA_TABLE = "CREATE TABLE " + DataEntry.TABLE_NAME + " (" +
+ DataEntry._ID + " INTEGER PRIMARY KEY, " +
+ DataEntry.COLUMN_CHARGE_FINISHED + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_TYPE + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_START + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_START_PERCENTAGE + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_START_VOLTAGE + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_START_TEMPERATURE_C + " REAL NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_STOP + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_STOP_PERCENTAGE + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_STOP_VOLTAGE + " INTEGER NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_STOP_TEMPERATURE_C + " REAL NOT NULL DEFAULT 0, " +
+ DataEntry.COLUMN_NOTE + " TEXT DEFAULT NULL " +
+ " );";
+
+ db.execSQL(SQL_CREATE_DATA_TABLE);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + DataEntry.TABLE_NAME);
+ onCreate(db);
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/data/receiver/PowerConnectionReceiver.java b/app/src/main/java/net/kacpak/batterychargingmonitor/data/receiver/PowerConnectionReceiver.java
new file mode 100644
index 0000000..c4d6307
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/data/receiver/PowerConnectionReceiver.java
@@ -0,0 +1,86 @@
+package net.kacpak.batterychargingmonitor.data.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import android.widget.Toast;
+
+import net.kacpak.batterychargingmonitor.R;
+import net.kacpak.batterychargingmonitor.data.BatteryDataRepository;
+import net.kacpak.batterychargingmonitor.data.BatteryStatus;
+
+import java.util.Date;
+
+public class PowerConnectionReceiver extends BroadcastReceiver {
+
+ private Context mContext;
+ private BatteryStatus mBatteryStatus;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mContext = context;
+ mBatteryStatus = new BatteryStatus();
+ showBatteryStatus();
+
+ if (mBatteryStatus.isCharging())
+ startNewCharging();
+ else
+ finishCharging();
+ }
+
+ public void showBatteryStatus() {
+ StringBuilder data = new StringBuilder();
+
+ data.append(String.format(mContext.getString(R.string.battery_percent), mBatteryStatus.getChargePercentage()));
+ data.append(" ");
+
+ if (mBatteryStatus.isCharging()) {
+ if (mBatteryStatus.isPluggedAC()) data.append(mContext.getString(R.string.battery_ac_charging));
+ if (mBatteryStatus.isPluggedUSB()) data.append(mContext.getString(R.string.battery_usb_charging));
+ if (mBatteryStatus.isPluggedWireless()) data.append(mContext.getString(R.string.battery_usb_charging));
+ } else {
+ data.append(mContext.getString(R.string.battery_disconnected));
+ }
+
+ data.append("\n");
+ data.append(String.format(mContext.getString(R.string.battery_temperature_celsius), mBatteryStatus.getTemperatureInCelsius()));
+
+ data.append(" ");
+ data.append(String.format(mContext.getString(R.string.battery_voltage), mBatteryStatus.getVoltage()));
+
+ Toast.makeText(mContext, data, Toast.LENGTH_SHORT).show();
+ }
+
+ public void startNewCharging() {
+ try {
+ new BatteryDataRepository(mContext).add(
+ new Date(),
+ mBatteryStatus.getPluggedInformation(),
+ mBatteryStatus.getChargePercentage(),
+ mBatteryStatus.getTemperatureInCelsius(),
+ mBatteryStatus.getVoltage()
+ );
+
+ } catch (Exception e) {
+ Log.e("startNewCharging", e.toString());
+ Toast.makeText(mContext, R.string.error_failed_to_start_charging, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ public void finishCharging() {
+ try {
+ new BatteryDataRepository(mContext).finishCharging(
+ new Date(),
+ mBatteryStatus.getChargePercentage(),
+ mBatteryStatus.getTemperatureInCelsius(),
+ mBatteryStatus.getVoltage(),
+ null
+ );
+
+ } catch (Exception e) {
+ Log.e("finishCharging", e.toString());
+ Toast.makeText(mContext, R.string.error_failed_complete_charging, Toast.LENGTH_SHORT).show();
+ }
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/MainActivity.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/MainActivity.java
index 6ce727b..bc852ad 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/MainActivity.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/MainActivity.java
@@ -1,6 +1,7 @@
package net.kacpak.batterychargingmonitor.ui;
import android.app.Fragment;
+import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
@@ -16,25 +17,34 @@
import net.kacpak.batterychargingmonitor.R;
import net.kacpak.batterychargingmonitor.ui.history.HistoryFragment;
+import net.kacpak.batterychargingmonitor.ui.settings.SettingsActivity;
import net.kacpak.batterychargingmonitor.ui.summary.SummaryFragment;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
public class MainActivity extends AppCompatActivity
- implements NavigationView.OnNavigationItemSelectedListener {
+ implements NavigationView.OnNavigationItemSelectedListener, NavigationDrawerManipulation {
+
+ @BindView(R.id.drawer_layout)
+ DrawerLayout mDrawer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
+ // ButterKnife
+ ButterKnife.bind(this);
+
// Toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Navigation Drawer
- DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
- this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
- drawer.setDrawerListener(toggle);
+ this, mDrawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
+ mDrawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
@@ -51,35 +61,25 @@ protected void onCreate(Bundle savedInstanceState) {
@Override
public void onBackPressed() {
- DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
- if (drawer.isDrawerOpen(GravityCompat.START))
- drawer.closeDrawer(GravityCompat.START);
+ if (mDrawer.isDrawerOpen(GravityCompat.START))
+ mDrawer.closeDrawer(GravityCompat.START);
else
super.onBackPressed();
}
@Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
+ public boolean onNavigationItemSelected(MenuItem item) {
+ final int id = item.getItemId();
- if (id == R.id.action_settings) {
+ // Ustawienia
+ if (id == R.id.nav_settings) {
+ mDrawer.closeDrawer(GravityCompat.START);
+ startActivity(new Intent(this, SettingsActivity.class));
return true;
}
- return super.onOptionsItemSelected(item);
- }
-
- @Override
- public boolean onNavigationItemSelected(MenuItem item) {
- final int id = item.getItemId();
+ // Zmiana fragmentu
Fragment fragment = null;
-
if (id == R.id.nav_summary)
fragment = new SummaryFragment();
else if (id == R.id.nav_history)
@@ -90,8 +90,24 @@ else if (id == R.id.nav_history)
.replace(R.id.content, fragment)
.commit();
- DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
- drawer.closeDrawer(GravityCompat.START);
+ mDrawer.closeDrawer(GravityCompat.START);
+ return true;
+ }
+
+ @Override
+ public boolean disableNavigationDrawer() {
+ if (mDrawer == null) return false;
+
+ mDrawer.closeDrawers();
+ mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+ return true;
+ }
+
+ @Override
+ public boolean enableNavigationDrawer() {
+ if (mDrawer == null) return false;
+
+ mDrawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
return true;
}
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/NavigationDrawerManipulation.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/NavigationDrawerManipulation.java
new file mode 100644
index 0000000..f664438
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/NavigationDrawerManipulation.java
@@ -0,0 +1,6 @@
+package net.kacpak.batterychargingmonitor.ui;
+
+public interface NavigationDrawerManipulation {
+ boolean disableNavigationDrawer();
+ boolean enableNavigationDrawer();
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryAdapter.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryAdapter.java
new file mode 100644
index 0000000..1ae0dcb
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryAdapter.java
@@ -0,0 +1,85 @@
+package net.kacpak.batterychargingmonitor.ui.history;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.os.BatteryManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CursorAdapter;
+import android.widget.TextView;
+
+import net.kacpak.batterychargingmonitor.R;
+import net.kacpak.batterychargingmonitor.data.database.ChargeInformation;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class HistoryAdapter extends CursorAdapter {
+
+ HistoryAdapter(Context context, Cursor cursor) {
+ super(context, cursor, 0);
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_history, parent, false);
+ view.setTag(new HistoryAdapterViewHolder(view));
+ return view;
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ ChargeInformation data = new ChargeInformation(cursor);
+
+ String type;
+ switch (data.getType()) {
+ case 0:
+ type = context.getString(R.string.power_state_mixed);
+ break;
+ case BatteryManager.BATTERY_PLUGGED_AC:
+ type = context.getString(R.string.power_state_ac);
+ break;
+ case BatteryManager.BATTERY_PLUGGED_USB:
+ type = context.getString(R.string.power_state_usb);
+ break;
+ case BatteryManager.BATTERY_PLUGGED_WIRELESS:
+ type = context.getString(R.string.power_state_wireless);
+ break;
+ default:
+ type = "?";
+ }
+
+ long seconds = data.getDuration() / 1000 % 60;
+ long minutes = data.getDuration() / (60 * 1000) % 60;
+ long hours = data.getDuration() / (60 * 60 * 1000);
+ String duration = String.format(context.getString(R.string.history_list_item_duration), hours, minutes, seconds);
+
+ String percentageIncrease = data.isFinished()
+ ? String.format(context.getString(R.string.history_list_item_percentage_increase), data.getStartPercentage(), data.getStopPercentage())
+ : String.format(context.getString(R.string.history_list_item_percentage_while_charging), data.getStartPercentage());
+
+ HistoryAdapterViewHolder holder = (HistoryAdapterViewHolder) view.getTag();
+ holder.type.setText(type);
+ holder.duration.setText(duration);
+ holder.percentage_increase.setText(percentageIncrease);
+ }
+
+ /**
+ * ViewHolder dla wiersza w historii
+ */
+ public class HistoryAdapterViewHolder {
+ @BindView(R.id.type)
+ public TextView type;
+
+ @BindView(R.id.duration)
+ public TextView duration;
+
+ @BindView(R.id.percentage_increase)
+ public TextView percentage_increase;
+
+ public HistoryAdapterViewHolder(View itemView) {
+ ButterKnife.bind(this, itemView);
+ }
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryContract.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryContract.java
index bf2f318..ced72b4 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryContract.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryContract.java
@@ -1,9 +1,24 @@
package net.kacpak.batterychargingmonitor.ui.history;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+
+import java.util.List;
+
public interface HistoryContract {
interface View {
+ void swapCursor(Cursor cursor);
+ void showDeletedCountMessage(int count);
+ void showMergedCountMessage(int count);
}
interface UserActionsListener {
+ Loader onCreateLoader(int id, Bundle args);
+ void onLoadFinished(Cursor data);
+ void onLoaderReset();
+ void removeIrrelevantEntries();
+ void removeEntries(List entries);
+ void mergeEntries(List entries);
}
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryFragment.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryFragment.java
index 861a94e..2d5dc3d 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryFragment.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryFragment.java
@@ -1,7 +1,244 @@
package net.kacpak.batterychargingmonitor.ui.history;
+import android.app.AlertDialog;
+import android.app.DialogFragment;
import android.app.Fragment;
+import android.app.LoaderManager;
+import android.content.DialogInterface;
+import android.content.Loader;
+import android.database.Cursor;
+import android.graphics.Color;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.Toast;
-public class HistoryFragment extends Fragment implements HistoryContract.View {
+import net.kacpak.batterychargingmonitor.R;
+import net.kacpak.batterychargingmonitor.data.BatteryStatus;
+import net.kacpak.batterychargingmonitor.ui.NavigationDrawerManipulation;
+import net.kacpak.batterychargingmonitor.ui.historydetail.HistoryDetailContract;
+import net.kacpak.batterychargingmonitor.ui.historydetail.HistoryDetailDialog;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class HistoryFragment extends Fragment implements
+ HistoryContract.View, LoaderManager.LoaderCallbacks,
+ AdapterView.OnItemClickListener, AbsListView.MultiChoiceModeListener {
+
+ /**
+ * ID dla nowo-tworzonego Loadera
+ */
+ private static final int HISTORY_LOADER = 0;
+
+ /**
+ * Interaktor
+ */
+ private HistoryContract.UserActionsListener mActionsListener;
+
+ /**
+ * RecyclerView do wyświetlenia historii ładowań telefony
+ */
+ @BindView(R.id.listview_history)
+ ListView mListView;
+
+ /**
+ * Adapter obsługujący wyświetlanie poszczególnych wpisów z bazy
+ */
+ private HistoryAdapter mHistoryAdapter;
+
+ /**
+ * Initializer
+ */
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ mActionsListener = new HistoryPresenter(this, getActivity());
+ getActivity().setTitle(R.string.title_history);
+ getLoaderManager().initLoader(HISTORY_LOADER, null, this);
+
+ super.onActivityCreated(savedInstanceState);
+ }
+
+ /**
+ * Tworzy widok naszego Fragmentu
+ */
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.content_history, container, false);
+ ButterKnife.bind(this, root);
+ setHasOptionsMenu(true);
+
+ mHistoryAdapter = new HistoryAdapter(getActivity(), null);
+
+ mListView.setAdapter(mHistoryAdapter);
+ mListView.setOnItemClickListener(this);
+ mListView.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
+ mListView.setMultiChoiceModeListener(this);
+// mListView.setEmptyView(null);
+
+ return root;
+ }
+
+ @Override
+ public Loader onCreateLoader(int id, Bundle args) {
+ return mActionsListener.onCreateLoader(id, args);
+ }
+
+ @Override
+ public void onLoadFinished(Loader loader, Cursor data) {
+ mActionsListener.onLoadFinished(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader loader) {
+ mActionsListener.onLoaderReset();
+ }
+
+ @Override
+ public void swapCursor(Cursor cursor) {
+ mHistoryAdapter.swapCursor(cursor);
+ }
+
+ @Override
+ public void showDeletedCountMessage(int count) {
+ Toast.makeText(getActivity(), getString(R.string.history_list_counted_entries_deleted, count), Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void showMergedCountMessage(int count) {
+ Toast.makeText(getActivity(), getString(R.string.history_list_counted_entries_merged, count), Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onItemClick(AdapterView> parent, View view, int position, long id) {
+ Cursor cursor = (Cursor) parent.getItemAtPosition(position);
+ if (cursor != null) {
+ Bundle args = new Bundle();
+ args.putLong(HistoryDetailContract.CHARGE_ID, cursor.getLong(0));
+
+ DialogFragment fragment = new HistoryDetailDialog();
+ fragment.setArguments(args);
+ fragment.show(getFragmentManager(), "dialog");
+ }
+ }
+
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
+ // Jeśli jest zaznaczony ostatni wpis w trakcie ładowania, dezaktywuj usuwanie
+ mode.getMenu().findItem(R.id.action_delete).setEnabled(
+ !(mListView.getCheckedItemPositions().get(0) && new BatteryStatus().isCharging()));
+
+ // Jeśli zaznaczeń są conajmniej 2, to aktywuj łączenie
+ mode.getMenu().findItem(R.id.action_merge).setEnabled(mListView.getCheckedItemCount() > 1);
+
+ String title = String.format(getString(R.string.history_list_selected_count), mListView.getCheckedItemCount());
+ mode.setTitle(title);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.menu_history, menu);
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ // Inflate menu for CAB (Contextual Action Bar)
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.menu_history_contextual, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {switch (item.getItemId()) {
+ case R.id.action_clear_entries:
+ mActionsListener.removeIrrelevantEntries();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
+ getActivity().getWindow().setStatusBarColor(
+ getResources().getColor(R.color.colorPrimaryDark)
+ );
+ }
+
+ ((NavigationDrawerManipulation) getActivity()).disableNavigationDrawer();
+ return true;
+ }
+
+ @Override
+ public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
+ final int id = item.getItemId();
+
+ DialogInterface.OnClickListener positiveAnswer = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (id == R.id.action_delete)
+ mActionsListener.removeEntries(getSelectedEntriesIds());
+ else
+ mActionsListener.mergeEntries(getSelectedEntriesIds());
+ mode.finish();
+ }
+ };
+
+ final int message = (id == R.id.action_delete) ? R.string.history_list_confirm_delete : R.string.history_list_confirm_merge;
+
+ new AlertDialog.Builder(getActivity())
+ .setTitle(android.R.string.dialog_alert_title)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.yes, positiveAnswer)
+ .setNegativeButton(android.R.string.no, null)
+ .show();
+
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
+ getActivity().getWindow().setStatusBarColor(Color.TRANSPARENT);
+ }
+
+ ((NavigationDrawerManipulation) getActivity()).enableNavigationDrawer();
+ }
+
+ /**
+ * Zwraca id zaznaczonych elementów
+ * @return lista z id zaznaczonych elementów
+ */
+ private List getSelectedEntriesIds() {
+ List ids = new ArrayList<>();
+ SparseBooleanArray positions = mListView.getCheckedItemPositions();
+
+ for (int i = 0; i < positions.size(); i++) {
+ if (positions.valueAt(i)) {
+ Cursor item = (Cursor) mHistoryAdapter.getItem(positions.keyAt(i));
+ ids.add(item.getLong(0));
+ }
+ }
+
+ return ids;
+ }
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryPresenter.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryPresenter.java
new file mode 100644
index 0000000..4a6f5ed
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/history/HistoryPresenter.java
@@ -0,0 +1,109 @@
+package net.kacpak.batterychargingmonitor.ui.history;
+
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Loader;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.widget.Toast;
+
+import net.kacpak.batterychargingmonitor.data.BatteryDataRepository;
+import net.kacpak.batterychargingmonitor.data.database.DatabaseContract.DataEntry;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+
+public class HistoryPresenter implements HistoryContract.UserActionsListener {
+
+ /**
+ * Kontekst aplikacji
+ */
+ private final WeakReference mContext;
+
+ /**
+ * Widok
+ */
+ private WeakReference mView;
+
+ /**
+ * Pobierane dane z bazy danych
+ */
+ private static final String[] sProjection = {
+ DataEntry._ID,
+ DataEntry.COLUMN_START,
+ DataEntry.COLUMN_STOP,
+ DataEntry.COLUMN_START_PERCENTAGE,
+ DataEntry.COLUMN_STOP_PERCENTAGE,
+ DataEntry.COLUMN_TYPE,
+ DataEntry.COLUMN_CHARGE_FINISHED
+ };
+
+ /**
+ * Tworzy Presenter dla widoku podsumowania ({@link HistoryContract.View}) z automatyczną aktualizacją
+ * @param mHistoryView Widok
+ * @param context Kontekst widoku
+ */
+ public HistoryPresenter(@NonNull HistoryContract.View mHistoryView, @NonNull Context context) {
+ mView = new WeakReference<>(mHistoryView);
+ mContext = new WeakReference<>(context);
+ }
+
+ /**
+ * Tworzy Loadera do wczytania danych o historii ładowania
+ * @param id id Loadera
+ * @param args dodatkowe argumenty
+ */
+ @Override
+ public Loader onCreateLoader(int id, Bundle args) {
+ return new CursorLoader(mContext.get(),
+ DataEntry.CONTENT_URI,
+ sProjection,
+ null,
+ null,
+ DataEntry.COLUMN_START + " DESC"
+ );
+ }
+
+ @Override
+ public void onLoadFinished(Cursor data) {
+ HistoryContract.View view = mView.get();
+ if (null != view)
+ view.swapCursor(data);
+ }
+
+ @Override
+ public void onLoaderReset() {
+ HistoryContract.View view = mView.get();
+ if (null != view)
+ view.swapCursor(null);
+ }
+
+ @Override
+ public void removeIrrelevantEntries() {
+ int deletedCount = new BatteryDataRepository(mContext.get()).deleteIrrelevant();
+
+ HistoryContract.View view = mView.get();
+ if (null != view)
+ view.showDeletedCountMessage(deletedCount);
+ }
+
+ @Override
+ public void removeEntries(List entries) {
+ int deletedCount = new BatteryDataRepository(mContext.get()).delete(entries);
+
+ HistoryContract.View view = mView.get();
+ if (null != view)
+ view.showDeletedCountMessage(deletedCount);
+ }
+
+ @Override
+ public void mergeEntries(List entries) {
+ int mergedCount = new BatteryDataRepository(mContext.get()).merge(entries);
+
+ HistoryContract.View view = mView.get();
+ if (null != view)
+ view.showMergedCountMessage(mergedCount);
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailContract.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailContract.java
new file mode 100644
index 0000000..ccf34de
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailContract.java
@@ -0,0 +1,24 @@
+package net.kacpak.batterychargingmonitor.ui.historydetail;
+
+import java.util.Date;
+
+public interface HistoryDetailContract {
+
+ String CHARGE_ID = "id";
+
+ interface View {
+ void setChargerType(int chargerType);
+ void setChargingStartDate(Date chargingStartDate);
+ void setChargingDuration(long hours, long minutes, long seconds);
+ void setChargeBump(int startingPercentage);
+ void setChargeBump(int startingPercentage, int finishedPercentage);
+ void setStartingTemperature(float startingTemperature);
+ void setFinishedTemperature(float finishedTemperature);
+ void setStartingVoltage(int startingVoltage);
+ void setFinishedVoltage(int finishedVoltage);
+ }
+
+ interface UserActionsListener {
+ void updateDetails();
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailDialog.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailDialog.java
new file mode 100644
index 0000000..9267294
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailDialog.java
@@ -0,0 +1,166 @@
+package net.kacpak.batterychargingmonitor.ui.historydetail;
+
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.os.BatteryManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.TextView;
+
+import net.kacpak.batterychargingmonitor.R;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+import static net.kacpak.batterychargingmonitor.ui.historydetail.HistoryDetailContract.*;
+
+/**
+ * Detale danego wpisu z historii
+ */
+public class HistoryDetailDialog extends DialogFragment implements HistoryDetailContract.View {
+
+// public static final SimpleDateFormat sDateFormat = new SimpleDateFormat("d MMM yyyy H:mm");
+ public static final DateFormat sDateFormat = SimpleDateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
+
+ @BindView(R.id.duration)
+ TextView mDurationTextView;
+
+ @BindView(R.id.charger_type)
+ TextView mChargerTypeTextView;
+
+ @BindView(R.id.start_date)
+ TextView mChargingStartTextView;
+
+ @BindView(R.id.start_temp)
+ TextView mTemperatureStartTextView;
+
+ @BindView(R.id.stop_temp)
+ TextView mTemperatureStopTextView;
+
+ @BindView(R.id.start_voltage)
+ TextView mVoltageStartTextView;
+
+ @BindView(R.id.stop_voltage)
+ TextView mVoltageStopTextView;
+
+ @BindView(R.id.charge_bump)
+ TextView mPercentageTextView;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ Dialog dialog = super.onCreateDialog(savedInstanceState);
+ dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+ return dialog;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.dialog_history_detail, container, false);
+ ButterKnife.bind(this, root);
+
+ Bundle args = getArguments();
+ if (null != args && args.containsKey(CHARGE_ID)) {
+ long id = args.getLong(CHARGE_ID);
+
+ UserActionsListener mActionsListener = new HistoryDetailPresenter(this, getActivity(), id);
+ mActionsListener.updateDetails();
+ }
+
+ return root;
+ }
+
+ @Override
+ public void setChargerType(int chargerType) {
+ String type;
+ switch (chargerType) {
+ case 0:
+ type = getString(R.string.power_state_mixed);
+ break;
+ case BatteryManager.BATTERY_PLUGGED_AC:
+ type = getString(R.string.power_state_ac);
+ break;
+ case BatteryManager.BATTERY_PLUGGED_USB:
+ type = getString(R.string.power_state_usb);
+ break;
+ case BatteryManager.BATTERY_PLUGGED_WIRELESS:
+ type = getString(R.string.power_state_wireless);
+ break;
+ default:
+ type = getString(R.string.power_state_unknown);
+ }
+ mChargerTypeTextView.setText(type);
+ }
+
+ @Override
+ public void setChargingStartDate(Date chargingStartDate) {
+ mChargingStartTextView.setText(
+ sDateFormat.format(chargingStartDate)
+ );
+ }
+
+ @Override
+ public void setChargingDuration(long hours, long minutes, long seconds) {
+ mDurationTextView.setText(String.format(
+ getString(R.string.history_list_item_duration),
+ hours, minutes, seconds
+ ));
+ }
+
+ @Override
+ public void setChargeBump(int startingPercentage) {
+ mPercentageTextView.setText(String.format(
+ getString(R.string.history_list_item_percentage_while_charging),
+ startingPercentage
+ ));
+ }
+
+ @Override
+ public void setChargeBump(int startingPercentage, int finishedPercentage) {
+ mPercentageTextView.setText(String.format(
+ getString(R.string.history_list_item_percentage_increase),
+ startingPercentage,
+ finishedPercentage
+ ));
+ }
+
+ @Override
+ public void setStartingTemperature(float startingTemperature) {
+ mTemperatureStartTextView.setText(String.format(
+ getString(R.string.temperature_celsius),
+ startingTemperature
+ ));
+ }
+
+ @Override
+ public void setFinishedTemperature(float finishedTemperature) {
+ mTemperatureStopTextView.setText(String.format(
+ getString(R.string.temperature_celsius),
+ finishedTemperature
+ ));
+ }
+
+ @Override
+ public void setStartingVoltage(int startingVoltage) {
+ mVoltageStartTextView.setText(String.format(
+ getString(R.string.voltage),
+ startingVoltage
+ ));
+ }
+
+ @Override
+ public void setFinishedVoltage(int finishedVoltage) {
+ mVoltageStopTextView.setText(String.format(
+ getString(R.string.voltage),
+ finishedVoltage
+ ));
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailPresenter.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailPresenter.java
new file mode 100644
index 0000000..4480913
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/historydetail/HistoryDetailPresenter.java
@@ -0,0 +1,62 @@
+package net.kacpak.batterychargingmonitor.ui.historydetail;
+
+import android.content.Context;
+
+import net.kacpak.batterychargingmonitor.data.BatteryDataRepository;
+import net.kacpak.batterychargingmonitor.data.database.ChargeInformation;
+
+import java.lang.ref.WeakReference;
+
+public class HistoryDetailPresenter implements HistoryDetailContract.UserActionsListener {
+
+ private WeakReference mHistoryDetailView;
+
+ private ChargeInformation mChargeInformation;
+
+ public HistoryDetailPresenter(HistoryDetailContract.View historyDetailView, Context context, long chargeId) {
+ mHistoryDetailView = new WeakReference<>(historyDetailView);
+ mChargeInformation = new BatteryDataRepository(context).getChargeInformation(chargeId);
+ }
+
+ @Override
+ public void updateDetails() {
+ HistoryDetailContract.View view = mHistoryDetailView.get();
+
+ if (null == view)
+ return;
+
+ // Initial battery charge
+ view.setChargeBump(mChargeInformation.getStartPercentage());
+
+ // Charger Type
+ view.setChargerType(mChargeInformation.getType());
+
+ // Duration
+ long seconds = mChargeInformation.getDuration() / 1000 % 60;
+ long minutes = mChargeInformation.getDuration() / (60 * 1000) % 60;
+ long hours = mChargeInformation.getDuration() / (60 * 60 * 1000);
+ view.setChargingDuration(hours, minutes, seconds);
+
+ // Starting Date
+ view.setChargingStartDate(mChargeInformation.getStartDate());
+
+ // Starting Temperature
+ view.setStartingTemperature(mChargeInformation.getStartTemperature());
+
+ // Starting Voltage
+ view.setStartingVoltage(mChargeInformation.getStartVoltage());
+
+ // If charging finished
+ if (!mChargeInformation.isFinished())
+ return;
+
+ // Charge Bump
+ view.setChargeBump(mChargeInformation.getStartPercentage(), mChargeInformation.getStopPercentage());
+
+ // Finished Temperature
+ view.setFinishedTemperature(mChargeInformation.getStopTemperature());
+
+ // Finished Voltage
+ view.setFinishedVoltage(mChargeInformation.getStopVoltage());
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/settings/SettingsActivity.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/settings/SettingsActivity.java
new file mode 100644
index 0000000..3e7b408
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/settings/SettingsActivity.java
@@ -0,0 +1,28 @@
+package net.kacpak.batterychargingmonitor.ui.settings;
+
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+
+import net.kacpak.batterychargingmonitor.R;
+
+public class SettingsActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_no_navigation);
+
+ // Toolbar
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+
+ if (savedInstanceState == null) {
+ getFragmentManager().beginTransaction()
+ .add(R.id.content, new SettingsFragment())
+ .commit();
+ }
+ }
+
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/settings/SettingsFragment.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/settings/SettingsFragment.java
new file mode 100644
index 0000000..c4b6120
--- /dev/null
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/settings/SettingsFragment.java
@@ -0,0 +1,14 @@
+package net.kacpak.batterychargingmonitor.ui.settings;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+import net.kacpak.batterychargingmonitor.R;
+
+public class SettingsFragment extends PreferenceFragment {
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.settings);
+ }
+}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryContract.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryContract.java
index 81ae549..a4c9f5b 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryContract.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryContract.java
@@ -1,20 +1,23 @@
package net.kacpak.batterychargingmonitor.ui.summary;
-import android.support.annotation.IdRes;
import android.support.annotation.IntRange;
+import android.support.annotation.StringRes;
public interface SummaryContract {
interface View {
void setBatteryChargeIndicator(@IntRange(from=0,to=100) int percentage);
- void setBatteryHealth(@IdRes int healthId);
+ void setBatteryHealth(@StringRes int healthId);
void setBatteryVoltage(int voltage);
- void setBatteryAmperage(int amperage);
- void setBatteryTemperature(double temperature);
+ void setBatteryCurrent(int current);
+ void setBatteryCurrent(int current, int currentAvg);
+ void setBatteryTemperatureInCelsius(double temperature);
+ void setBatteryTemperatureInFahrenheit(double temperature);
void setBatteryChargingCounter(int counter);
+ void hideBatteryCurrentData();
}
interface UserActionsListener {
- void updateAllData();
+ void updateView();
void startUpdates();
void stopUpdates();
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryFragment.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryFragment.java
index 5de5656..a296f90 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryFragment.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryFragment.java
@@ -1,19 +1,26 @@
package net.kacpak.batterychargingmonitor.ui.summary;
import android.app.Fragment;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.IntRange;
import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.TextView;
import com.github.lzyzsd.circleprogress.DonutProgress;
import net.kacpak.batterychargingmonitor.R;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
public class SummaryFragment extends Fragment implements SummaryContract.View {
@@ -25,7 +32,7 @@ public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
- mActionsListener = new SummaryPresenter(this);
+ mActionsListener = new SummaryPresenter(this, getActivity());
getActivity().setTitle(R.string.title_summary);
}
@@ -34,9 +41,37 @@ public void onActivityCreated(Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.content_summary, container, false);
ButterKnife.bind(this, root);
+ setHasOptionsMenu(true);
return root;
}
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.menu_summary, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.action_battery_settings)
+ return showPowerUsage();
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * Uruchamia domyślną aplikację monitorującą zużycie baterii
+ */
+ private boolean showPowerUsage() {
+ Intent powerUsageIntent = new Intent(Intent.ACTION_POWER_USAGE_SUMMARY);
+ ResolveInfo resolveInfo = getActivity().getPackageManager().resolveActivity(powerUsageIntent, 0);
+
+ // Check that the Battery app exists on this device
+ if (resolveInfo != null)
+ startActivity(powerUsageIntent);
+
+ return true;
+ }
+
@Override
public void onResume() {
super.onResume();
@@ -44,12 +79,12 @@ public void onResume() {
}
@Override
- public void onStop() {
- super.onStop();
+ public void onPause() {
+ super.onPause();
mActionsListener.stopUpdates();
}
- @Bind(R.id.battery_charge_indicator)
+ @BindView(R.id.battery_charge_indicator)
DonutProgress mBatteryChargeIndicator;
@Override
@@ -57,28 +92,69 @@ public void setBatteryChargeIndicator(@IntRange(from = 0, to = 100) int percenta
mBatteryChargeIndicator.setProgress(percentage);
}
- @Override
- public void setBatteryHealth(@IdRes int healthId) {
+ @BindView(R.id.health)
+ TextView mBatteryHealth;
+ @Override
+ public void setBatteryHealth(@StringRes int healthId) {
+ mBatteryHealth.setText(healthId);
}
+ @BindView(R.id.voltage)
+ TextView mBatteryVoltage;
+
@Override
public void setBatteryVoltage(int voltage) {
+ mBatteryVoltage.setText(String.format(getString(R.string.voltage), voltage));
+ }
+
+ @BindView(R.id.current)
+ TextView mBatteryCurrent;
+ @Override
+ public void setBatteryCurrent(int current) {
+ mBatteryCurrent.setText(String.format(getString(R.string.current), current));
}
@Override
- public void setBatteryAmperage(int amperage) {
+ public void setBatteryCurrent(int current, int currentAvg) {
+ String currentTxt = new StringBuilder()
+ .append(String.format(getString(R.string.current), current))
+ .append(" (")
+ .append(String.format(getString(R.string.current), currentAvg))
+ .append(')')
+ .toString();
+
+ mBatteryCurrent.setText(currentTxt);
+ }
+
+ @BindView(R.id.current_heading)
+ TextView mBatteryCurrentHeading;
+ @Override
+ public void hideBatteryCurrentData() {
+ mBatteryCurrent.setVisibility(View.GONE);
+ mBatteryCurrentHeading.setVisibility(View.GONE);
}
+ @BindView(R.id.temperature)
+ TextView mBatteryTemperature;
+
@Override
- public void setBatteryTemperature(double temperature) {
+ public void setBatteryTemperatureInCelsius(double temperature) {
+ mBatteryTemperature.setText(String.format(getString(R.string.temperature_celsius), temperature));
+ }
+ @Override
+ public void setBatteryTemperatureInFahrenheit(double temperature) {
+ mBatteryTemperature.setText(String.format(getString(R.string.temperature_fahrenheit), temperature));
}
+ @BindView(R.id.counter)
+ TextView mBatteryChargingCounter;
+
@Override
public void setBatteryChargingCounter(int counter) {
-
+ mBatteryChargingCounter.setText(String.format(getString(R.string.count_times), counter));
}
}
diff --git a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryPresenter.java b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryPresenter.java
index 04748bc..bfa50b5 100644
--- a/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryPresenter.java
+++ b/app/src/main/java/net/kacpak/batterychargingmonitor/ui/summary/SummaryPresenter.java
@@ -1,10 +1,15 @@
package net.kacpak.batterychargingmonitor.ui.summary;
+import android.content.Context;
import android.os.Handler;
import android.support.annotation.NonNull;
+import net.kacpak.batterychargingmonitor.R;
import net.kacpak.batterychargingmonitor.data.BatteryDataRepository;
import net.kacpak.batterychargingmonitor.data.BatteryStatus;
+import net.kacpak.batterychargingmonitor.data.UserPreferences;
+
+import java.lang.ref.WeakReference;
public class SummaryPresenter implements SummaryContract.UserActionsListener {
@@ -16,7 +21,12 @@ public class SummaryPresenter implements SummaryContract.UserActionsListener {
/**
* Widok
*/
- private final SummaryContract.View mSummaryView;
+ private final WeakReference mView;
+
+ /**
+ * Kontekst aplikacji
+ */
+ private final Context mContext;
/**
* Wskazuje czy należy zaktualizować widok
@@ -28,28 +38,75 @@ public class SummaryPresenter implements SummaryContract.UserActionsListener {
*/
private BatteryStatus mBatteryStatus;
+ private Handler mRunnableHandler;
+ private Runnable mUpdater;
+
/**
* Tworzy Presenter dla widoku podsumowania ({@link SummaryContract.View}) z automatyczną aktualizacją
- * @param mSummaryView
+ * @param view
*/
- public SummaryPresenter(@NonNull SummaryContract.View mSummaryView) {
- this.mSummaryView = mSummaryView;
+ public SummaryPresenter(@NonNull SummaryContract.View view, Context context) {
+ mView = new WeakReference<>(view);
+ mContext = context;
updateBatteryStatus();
+ updateView();
}
/**
* Aktualizuje obecny stan baterii
*/
private void updateBatteryStatus() {
- mBatteryStatus = new BatteryDataRepository().getStatus();
+ mBatteryStatus = new BatteryDataRepository(mContext).getStatus();
}
/**
* Aktualizuje dane interfejsu użytkownika
*/
@Override
- public void updateAllData() {
- mSummaryView.setBatteryChargeIndicator(mBatteryStatus.getPercentage());
+ public void updateView() {
+ SummaryContract.View view = mView.get();
+
+ if (null == view)
+ return;
+
+ // Obecny stan naładowania baterii w procentach
+ view.setBatteryChargeIndicator(mBatteryStatus.getChargePercentage());
+
+ // Obecna temperatura baterii w wybranej jednostce
+ if (new UserPreferences(mContext).isTemperatureInCelsius())
+ view.setBatteryTemperatureInCelsius(mBatteryStatus.getTemperatureInCelsius());
+ else
+ view.setBatteryTemperatureInFahrenheit(mBatteryStatus.getTemperatureInFahrenheit());
+
+ // Napięcie na baterii
+ view.setBatteryVoltage(mBatteryStatus.getVoltage());
+
+ // Natężenie prądu
+ if (mBatteryStatus.isCurrentAvailable()) {
+ if (mBatteryStatus.isCurrentAverageAvailable())
+ view.setBatteryCurrent(mBatteryStatus.getCurrent(), mBatteryStatus.getCurrentAverage());
+ else
+ view.setBatteryCurrent(mBatteryStatus.getCurrent());
+ } else
+ view.hideBatteryCurrentData();
+
+ // Stan zdrowia baterii
+ int healthStringId;
+ switch (mBatteryStatus.getHealthInformation()) {
+ case 2: healthStringId = R.string.health_good; break;
+ case 3: healthStringId = R.string.health_overheat; break;
+ case 4: healthStringId = R.string.health_dead; break;
+ case 5: healthStringId = R.string.health_over_voltage; break;
+ case 6: healthStringId = R.string.health_unspecified_failure; break;
+ case 7: healthStringId = R.string.health_cold; break;
+ default: healthStringId = R.string.health_unknown;
+ }
+ view.setBatteryHealth(healthStringId);
+
+ // Licznik ładowań
+ view.setBatteryChargingCounter(
+ new BatteryDataRepository(mContext).getChargedCount()
+ );
}
/**
@@ -59,18 +116,21 @@ public void updateAllData() {
public void startUpdates() {
mUpdateData = true;
- final Handler handler = new Handler();
- final Runnable updateTask = new Runnable() {
+ if (mRunnableHandler != null)
+ mRunnableHandler.removeCallbacks(mUpdater);
+
+ mRunnableHandler = new Handler();
+ mUpdater = new Runnable() {
@Override
public void run() {
if (mUpdateData) {
updateBatteryStatus();
- updateAllData();
- handler.postDelayed(this, DATA_UPDATE_INTERVAL);
+ updateView();
+ mRunnableHandler.postDelayed(mUpdater, DATA_UPDATE_INTERVAL);
}
}
};
- handler.postDelayed(updateTask, DATA_UPDATE_INTERVAL);
+ mRunnableHandler.postDelayed(mUpdater, DATA_UPDATE_INTERVAL);
}
/**
@@ -79,6 +139,8 @@ public void run() {
@Override
public void stopUpdates() {
mUpdateData = false;
+ if (mRunnableHandler != null)
+ mRunnableHandler.removeCallbacks(mUpdater);
}
}
diff --git a/app/src/main/res/drawable-nodpi/thunder.png b/app/src/main/res/drawable-nodpi/thunder.png
new file mode 100644
index 0000000..1328451
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/thunder.png differ
diff --git a/app/src/main/res/drawable-v21/ic_menu_gallery.xml b/app/src/main/res/drawable-v21/ic_menu_gallery.xml
deleted file mode 100644
index f6872c4..0000000
--- a/app/src/main/res/drawable-v21/ic_menu_gallery.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/history_list_selector.xml b/app/src/main/res/drawable/history_list_selector.xml
new file mode 100644
index 0000000..5d2fd9c
--- /dev/null
+++ b/app/src/main/res/drawable/history_list_selector.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_clear_all.xml b/app/src/main/res/drawable/ic_clear_all.xml
new file mode 100644
index 0000000..db78320
--- /dev/null
+++ b/app/src/main/res/drawable/ic_clear_all.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..e1696ce
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_delete_active.xml b/app/src/main/res/drawable/ic_delete_active.xml
new file mode 100644
index 0000000..0e434a1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete_active.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_delete_inactive.xml b/app/src/main/res/drawable/ic_delete_inactive.xml
new file mode 100644
index 0000000..ab60fe7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete_inactive.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_merge.xml b/app/src/main/res/drawable/ic_merge.xml
new file mode 100644
index 0000000..80e097f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_merge.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_merge_active.xml b/app/src/main/res/drawable/ic_merge_active.xml
new file mode 100644
index 0000000..2047132
--- /dev/null
+++ b/app/src/main/res/drawable/ic_merge_active.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_merge_inactive.xml b/app/src/main/res/drawable/ic_merge_inactive.xml
new file mode 100644
index 0000000..c23a328
--- /dev/null
+++ b/app/src/main/res/drawable/ic_merge_inactive.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
new file mode 100644
index 0000000..ace746c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_toolbar_battery_charging_active.xml b/app/src/main/res/drawable/ic_toolbar_battery_charging_active.xml
new file mode 100644
index 0000000..165e279
--- /dev/null
+++ b/app/src/main/res/drawable/ic_toolbar_battery_charging_active.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml
deleted file mode 100644
index 458b4b0..0000000
--- a/app/src/main/res/drawable/side_nav_bar.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/content_summary.xml b/app/src/main/res/layout-land/content_summary.xml
new file mode 100644
index 0000000..5be8d1c
--- /dev/null
+++ b/app/src/main/res/layout-land/content_summary.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity.xml b/app/src/main/res/layout/activity.xml
index 6ba9383..0d0ed76 100644
--- a/app/src/main/res/layout/activity.xml
+++ b/app/src/main/res/layout/activity.xml
@@ -21,7 +21,6 @@
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
- android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />
diff --git a/app/src/main/res/layout/activity_no_navigation.xml b/app/src/main/res/layout/activity_no_navigation.xml
new file mode 100644
index 0000000..85c2458
--- /dev/null
+++ b/app/src/main/res/layout/activity_no_navigation.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_history.xml b/app/src/main/res/layout/content_history.xml
new file mode 100644
index 0000000..8405d33
--- /dev/null
+++ b/app/src/main/res/layout/content_history.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_summary.xml b/app/src/main/res/layout/content_summary.xml
index 354c16a..7027e06 100644
--- a/app/src/main/res/layout/content_summary.xml
+++ b/app/src/main/res/layout/content_summary.xml
@@ -9,20 +9,35 @@
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
+ android:background="@color/colorWindowBackground"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".ui.MainActivity">
-
+
-
+
+
+
+ android:layout_marginBottom="24dp"
+ android:gravity="center">
+
+
+
+
diff --git a/app/src/main/res/layout/content_summary_card.xml b/app/src/main/res/layout/content_summary_card.xml
new file mode 100644
index 0000000..e7030e0
--- /dev/null
+++ b/app/src/main/res/layout/content_summary_card.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_history_detail.xml b/app/src/main/res/layout/dialog_history_detail.xml
new file mode 100644
index 0000000..490598e
--- /dev/null
+++ b/app/src/main/res/layout/dialog_history_detail.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_item_history.xml b/app/src/main/res/layout/list_item_history.xml
new file mode 100644
index 0000000..ce1b890
--- /dev/null
+++ b/app/src/main/res/layout/list_item_history.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/nav_header.xml b/app/src/main/res/layout/nav_header.xml
index fcc84ca..4a3ee95 100644
--- a/app/src/main/res/layout/nav_header.xml
+++ b/app/src/main/res/layout/nav_header.xml
@@ -2,7 +2,7 @@
+ android:src="@mipmap/ic_launcher" />
-
+
+
+
+
+
+
-
+
+
+
+
+
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
deleted file mode 100644
index a2411e3..0000000
--- a/app/src/main/res/menu/main.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
diff --git a/app/src/main/res/menu/menu_history.xml b/app/src/main/res/menu/menu_history.xml
new file mode 100644
index 0000000..2aa429d
--- /dev/null
+++ b/app/src/main/res/menu/menu_history.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_history_contextual.xml b/app/src/main/res/menu/menu_history_contextual.xml
new file mode 100644
index 0000000..0899b7c
--- /dev/null
+++ b/app/src/main/res/menu/menu_history_contextual.xml
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_summary.xml b/app/src/main/res/menu/menu_summary.xml
new file mode 100644
index 0000000..76778c9
--- /dev/null
+++ b/app/src/main/res/menu/menu_summary.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/nav_drawer.xml b/app/src/main/res/menu/nav_drawer.xml
index 1286f7c..34768c9 100644
--- a/app/src/main/res/menu/nav_drawer.xml
+++ b/app/src/main/res/menu/nav_drawer.xml
@@ -1,15 +1,20 @@
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index cde69bc..3d31866 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index c133a0c..0d8436a 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index bfa42f0..4ef8763 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 324e72c..1ead658 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index aee44e1..97691de 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index efee38f..d39ccec 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -6,4 +6,53 @@
Otwórz menu nawigacji
Historia
Podsumowanie
+ %1$d razy
+ Nieznane
+ Dobre
+ Przegrzanie
+ Martwa
+ Zbyt wysokie napięcie
+ Nieznane uszkodzenie
+ Zbyt zimna
+ Zdrowie
+ Temperatura
+ Napięcie
+ Natężenie
+ Ładowano
+ Zużycie Baterii
+ Bateria: %1$d%%.
+ Napięcie: %1$dmV.
+ Temperatura: %1$.1f°C.
+ Temperatura: %1$.1f°F.
+ Ładowano %1$d razy.
+ Odłączona.
+ Ładowanie normalne.
+ Ładowanie przez USB.
+ Ładowanie bezprzewodowe.
+ Nie udało sie zkończyć ładowania.
+ Nie udało się zapisać ładowania.
+ Liczba ładowań przed instalacją tej aplikacji
+ Poprzednie ładowania
+ Nieistotna długość ładowania
+ Minimalny czas w sekundach, po którym wpisy nie będą automatycznie usuwane
+ Temperatura
+ Temperatura w stopniach Fahrenheita
+ Temperatura w stopniach Celsjusza
+ Naładowanie
+ Typ Ładowarki
+ Czas Ładowania
+ Temperatura początkowa
+ Napięcie początkowe
+ Temperatura końcowa
+ Napięcie końcowe
+ Szczegóły Ładowania
+ Czy na pewno chcesz usunąć te wpisy?
+ Czy na pewno chcesz połączyć te wpisy?
+ Usunięto %1$d wpisów
+ Połączono %1$d wpisów
+ %1$dg %2$dm %3$ds
+ Usuń
+ Połącz
+ Zaznaczono: %1$d
+ Wyczyść zbędne wpisy
\ No newline at end of file
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
index 251fb9f..e70ac80 100644
--- a/app/src/main/res/values-v21/styles.xml
+++ b/app/src/main/res/values-v21/styles.xml
@@ -1,9 +1,12 @@
->
+
-
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 3ab3e9c..8ebd2b9 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,6 +1,18 @@
- #3F51B5
- #303F9F
- #FF4081
+ #C8E6C9
+ #4CAF50
+ #388E3C
+ #009688
+
+ #212121
+ #101010
+ #727272
+ #FFFFFF
+
+ #E5E5E5
+ #B6B6B6
+
+ #8B000000
+ #41000000
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index c2e2f02..16d36a3 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -2,9 +2,13 @@
16dp
160dp
+
16dp
16dp
16dp
- 200dp
+
+
+ 240dp
+ 320dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 7224cb3..5e8e399 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -8,4 +8,95 @@
Close navigation drawer
Settings
+
+
+ %1$d%%
+ %1$dmV
+ %1$dmA
+ %1$.1f°C
+ %1$.1f°F
+ %1$d times
+
+ - @string/health_unknown
+ - @string/health_good
+ - @string/health_overheat
+ - @string/health_dead
+ - @string/health_over_voltage
+ - @string/health_unspecified_failure
+ - @string/health_cold
+
+ Unknown
+ Good
+ Overheat
+ Dead
+ Over Voltage
+ Unspecified Failure
+ Cold
+ AC
+ USB
+ Wi
+ Mix
+ \?
+
+
+ Health
+ Temperature
+ Voltage
+ Current
+ Charged
+ Battery Usage
+
+
+ Battery: %1$d%%.
+ Voltage: %1$dmV.
+ Temperature: %1$.1f°C.
+ Temperature: %1$.1f°F.
+ Disconnected.
+ Charging with AC.
+ Charging with USB.
+ Charging with Wireless.
+ Charged %1$d times.
+
+
+ add_to_count
+ 0
+ Previous Charges
+ Number of charges before installing this app
+ irrelevant_duration
+ 5
+ Irrelevant Charging Duration
+ Minimum charging duration in seconds assuring entry won\'t be deleted
+ temperature_in_celsius
+ true
+ Temperature scale
+ Temperature in Celsius
+ Temperature in Fahrenheit
+
+
+ %1$d%% → %2$d%%
+ %1$d%% → ---
+ %1$dh %2$dm %3$ds
+ Selected: %1$d
+ Merge
+ Delete
+ Merged %1$d entries
+ Deleted %1$d entries
+ Do you really want to merge this items?
+ Do you really want to delete this items?
+ Clear Entries
+
+
+ Charging Details
+ Duration
+ Charge
+ Charger Type
+ Initial Temperature
+ Finished Temperature
+ Initial Voltage
+ Finished Voltage
+ ---
+
+
+ Failed to save this charging.
+ Failed to complete charging.
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 545b9c6..bf051e5 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,20 +1,39 @@
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml
new file mode 100644
index 0000000..04f25d2
--- /dev/null
+++ b/app/src/main/res/xml/settings.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index e0b366a..cc19335 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,8 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.5.0'
+ classpath 'com.android.tools.build:gradle:2.1.0'
+ classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f23df6e..b9e5d19 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Wed Oct 21 11:34:03 PDT 2015
+#Sat Apr 30 19:46:32 CEST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip