diff --git a/build.gradle b/build.gradle index 39b3898b..377f41a8 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,11 @@ buildscript { - ext.kotlin_version = '1.3.20' + ext.kotlin_version = '1.3.21' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.0' + classpath 'com.android.tools.build:gradle:3.3.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/src/androidTest/java/org/havenapp/main/database/migration/RoomMigrationTest.kt b/src/androidTest/java/org/havenapp/main/database/migration/RoomMigrationTest.kt index 1d94b574..eaa89451 100644 --- a/src/androidTest/java/org/havenapp/main/database/migration/RoomMigrationTest.kt +++ b/src/androidTest/java/org/havenapp/main/database/migration/RoomMigrationTest.kt @@ -1,9 +1,9 @@ package org.havenapp.main.database.migration -import androidx.test.core.app.ApplicationProvider import androidx.room.Room import androidx.room.testing.MigrationTestHelper import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory +import androidx.test.core.app.ApplicationProvider import androidx.test.platform.app.InstrumentationRegistry import junit.framework.Assert.assertEquals import org.havenapp.main.database.HavenEventDB diff --git a/src/androidTest/java/org/havenapp/main/database/migration/SugarDbOpenHelper.kt b/src/androidTest/java/org/havenapp/main/database/migration/SugarDbOpenHelper.kt index cac18038..e71a9be0 100644 --- a/src/androidTest/java/org/havenapp/main/database/migration/SugarDbOpenHelper.kt +++ b/src/androidTest/java/org/havenapp/main/database/migration/SugarDbOpenHelper.kt @@ -1,7 +1,6 @@ package org.havenapp.main.database.migration import android.content.Context -import android.content.Context.MODE_PRIVATE import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper diff --git a/src/main/java/org/havenapp/main/ListActivity.java b/src/main/java/org/havenapp/main/ListActivity.java index 1f8b8cb7..5bef658d 100644 --- a/src/main/java/org/havenapp/main/ListActivity.java +++ b/src/main/java/org/havenapp/main/ListActivity.java @@ -40,7 +40,6 @@ import com.mikepenz.aboutlibraries.Libs; import com.mikepenz.aboutlibraries.LibsBuilder; -import org.havenapp.main.R; import org.havenapp.main.database.HavenEventDB; import org.havenapp.main.database.async.EventDeleteAllAsync; import org.havenapp.main.database.async.EventDeleteAsync; diff --git a/src/main/java/org/havenapp/main/MonitorActivity.java b/src/main/java/org/havenapp/main/MonitorActivity.java index 22e30f63..529feaac 100644 --- a/src/main/java/org/havenapp/main/MonitorActivity.java +++ b/src/main/java/org/havenapp/main/MonitorActivity.java @@ -31,10 +31,6 @@ import android.widget.Button; import android.widget.TextView; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; - import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; import org.havenapp.main.service.MonitorService; @@ -47,6 +43,10 @@ import java.io.FileOutputStream; import java.io.IOException; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + import static org.havenapp.main.Utils.getTimerText; public class MonitorActivity extends AppCompatActivity implements TimePickerDialog.OnTimeSetListener { diff --git a/src/main/java/org/havenapp/main/PreferenceManager.java b/src/main/java/org/havenapp/main/PreferenceManager.java index 19fc0c85..fe29f875 100644 --- a/src/main/java/org/havenapp/main/PreferenceManager.java +++ b/src/main/java/org/havenapp/main/PreferenceManager.java @@ -55,6 +55,7 @@ public class PreferenceManager { public static final String CONFIG_MOVEMENT ="config_movement"; public static final String HEARTBEAT_MONITOR_ACTIVE="heartbeat_monitor_active"; public static final String HEARTBEAT_MONITOR_DELAY="heartbeat_monitor_delay"; + public static final String HEARTBEAT_MONITOR_MESSAGE="heartbeat_monitor_message"; public static final String MONITOR_SERVICE_ACTIVE="monitor_service_active"; private static final String FLASH_ACTIVE="flash_active"; private static final String MICROPHONE_ACTIVE="microphone_active"; @@ -351,6 +352,26 @@ public int getHeartbeatNotificationTimeMs () { return appSharedPrefs.getInt(HEARTBEAT_MONITOR_DELAY,300000); } + public String getHeartbeatMonitorMessage () + { + return appSharedPrefs.getString(HEARTBEAT_MONITOR_MESSAGE,null); + } + + public void setHeartbeatMonitorMessage (String hearbeatMessage) + { + prefsEditor.putString(HEARTBEAT_MONITOR_MESSAGE, hearbeatMessage); + prefsEditor.commit(); + } + + public String getHearbeatPrefix() { + return context.getString(R.string.hearbeat_monitor_initial_message_1); + } + + public String getHeartbeatSuffix() { + return context.getString(R.string.hearbeat_monitor_initial_message_2); + } + + /** * Set the {@link org.havenapp.main.model.Event#startTime} for the ongoing event. * Sets a string with the format {@link Utils#DATE_TIME_PATTERN} diff --git a/src/main/java/org/havenapp/main/SettingsActivity.java b/src/main/java/org/havenapp/main/SettingsActivity.java index 554bb55d..264eb8b6 100644 --- a/src/main/java/org/havenapp/main/SettingsActivity.java +++ b/src/main/java/org/havenapp/main/SettingsActivity.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.os.Bundle; import android.view.View; + import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; diff --git a/src/main/java/org/havenapp/main/SettingsFragment.java b/src/main/java/org/havenapp/main/SettingsFragment.java index fc28e169..ab69ca6c 100644 --- a/src/main/java/org/havenapp/main/SettingsFragment.java +++ b/src/main/java/org/havenapp/main/SettingsFragment.java @@ -22,16 +22,6 @@ import android.widget.Switch; import android.widget.Toast; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import androidx.core.content.ContextCompat; -import androidx.preference.EditTextPreference; -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.SwitchPreference; - import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.wdullaer.materialdatetimepicker.time.TimePickerDialog; @@ -44,6 +34,15 @@ import java.io.File; import java.util.Locale; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; +import androidx.preference.EditTextPreference; +import androidx.preference.ListPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.SwitchPreference; import info.guardianproject.netcipher.proxy.OrbotHelper; @@ -154,6 +153,13 @@ public void onCreatePreferences(Bundle bundle, String s) { findPreference(PreferenceManager.HEARTBEAT_MONITOR_DELAY).setSummary(preferences.getHeartbeatNotificationTimeMs() / 60000 + " " + getString(R.string.minutes)); } + if (preferences.getHeartbeatMonitorMessage() == null) + { + findPreference(PreferenceManager.HEARTBEAT_MONITOR_MESSAGE).setSummary(R.string.hearbeat_message_summary); + } else { + findPreference(PreferenceManager.HEARTBEAT_MONITOR_MESSAGE).setSummary(R.string.hearbeat_message_summary_on); + } + Preference prefCameraSensitivity = findPreference(PreferenceManager.CAMERA_SENSITIVITY); prefCameraSensitivity.setOnPreferenceClickListener(preference -> { startActivity(new Intent(mActivity, CameraConfigureActivity.class)); @@ -434,6 +440,19 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin } break; } + case PreferenceManager.HEARTBEAT_MONITOR_MESSAGE: { + String text = ((EditTextPreference) findPreference(PreferenceManager.HEARTBEAT_MONITOR_MESSAGE)).getText(); + + if (checkValidString(text)) { + preferences.setHeartbeatMonitorMessage(text); + findPreference(PreferenceManager.HEARTBEAT_MONITOR_MESSAGE).setSummary(R.string.hearbeat_message_summary_on); + } + else { + preferences.setHeartbeatMonitorMessage(null); + findPreference(PreferenceManager.HEARTBEAT_MONITOR_MESSAGE).setSummary(R.string.hearbeat_message_summary); + } + break; + } case PreferenceManager.CONFIG_BASE_STORAGE: { setDefaultStoragePath(); break; diff --git a/src/main/java/org/havenapp/main/Utils.java b/src/main/java/org/havenapp/main/Utils.java index be2e843f..6b9b07ef 100644 --- a/src/main/java/org/havenapp/main/Utils.java +++ b/src/main/java/org/havenapp/main/Utils.java @@ -1,5 +1,10 @@ package org.havenapp.main; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; + import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; @@ -46,4 +51,23 @@ static String getTimerText(long milliseconds) { public static String getDateTime(Date date) { return new SimpleDateFormat(DATE_TIME_PATTERN, Locale.getDefault()).format(date); } + + /** + * Get the battery level from the device, from official docs: + * https://developer.android.com/training/monitoring-device-state/battery-monitoring#MonitorLevel + * @param context + * @return an integer corresponding to the battery percentage without any symbols + */ + public static int getBatteryPercentage(Context context) { + + IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + Intent batteryStatus = context.registerReceiver(null, iFilter); + + int level = batteryStatus != null ? batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) : -1; + int scale = batteryStatus != null ? batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1) : -1; + + float batteryPct = level / (float) scale; + + return (int) (batteryPct * 100); + } } diff --git a/src/main/java/org/havenapp/main/model/EventTrigger.kt b/src/main/java/org/havenapp/main/model/EventTrigger.kt index 4b540fb4..a2f468c4 100644 --- a/src/main/java/org/havenapp/main/model/EventTrigger.kt +++ b/src/main/java/org/havenapp/main/model/EventTrigger.kt @@ -3,9 +3,9 @@ package org.havenapp.main.model import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.PrimaryKey +import org.havenapp.main.R import org.havenapp.main.resources.IResourceManager import java.util.* -import org.havenapp.main.R /** * Created by Arka Prava Basu on 22/5/18. diff --git a/src/main/java/org/havenapp/main/sensors/media/AudioCodec.java b/src/main/java/org/havenapp/main/sensors/media/AudioCodec.java index 8f11e125..3ee6f511 100644 --- a/src/main/java/org/havenapp/main/sensors/media/AudioCodec.java +++ b/src/main/java/org/havenapp/main/sensors/media/AudioCodec.java @@ -5,13 +5,14 @@ package org.havenapp.main.sensors.media; -import java.io.IOException; -import java.util.Arrays; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.util.Log; +import java.io.IOException; +import java.util.Arrays; + public class AudioCodec { private AudioRecord recorder = null; diff --git a/src/main/java/org/havenapp/main/sensors/media/ImageCodec.java b/src/main/java/org/havenapp/main/sensors/media/ImageCodec.java index a9cfa284..fcba217e 100644 --- a/src/main/java/org/havenapp/main/sensors/media/ImageCodec.java +++ b/src/main/java/org/havenapp/main/sensors/media/ImageCodec.java @@ -6,11 +6,11 @@ package org.havenapp.main.sensors.media; -import java.io.ByteArrayOutputStream; - import android.graphics.Bitmap; import android.graphics.Matrix; +import java.io.ByteArrayOutputStream; + public class ImageCodec { /** diff --git a/src/main/java/org/havenapp/main/sensors/media/MediaRecorderTask.java b/src/main/java/org/havenapp/main/sensors/media/MediaRecorderTask.java index 0632a482..c7903c3c 100644 --- a/src/main/java/org/havenapp/main/sensors/media/MediaRecorderTask.java +++ b/src/main/java/org/havenapp/main/sensors/media/MediaRecorderTask.java @@ -3,7 +3,6 @@ import android.hardware.Camera; import android.media.MediaRecorder; import android.util.Log; -import android.view.Surface; import android.view.SurfaceHolder; import java.io.IOException; diff --git a/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java b/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java index e32f47f2..9edd47dd 100644 --- a/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java +++ b/src/main/java/org/havenapp/main/sensors/motion/MotionDetector.java @@ -16,7 +16,6 @@ import android.graphics.YuvImage; import android.os.Handler; - import org.havenapp.main.sensors.media.ImageCodec; import java.io.ByteArrayOutputStream; diff --git a/src/main/java/org/havenapp/main/service/MonitorService.java b/src/main/java/org/havenapp/main/service/MonitorService.java index 13d7eff4..0afc1fdd 100644 --- a/src/main/java/org/havenapp/main/service/MonitorService.java +++ b/src/main/java/org/havenapp/main/service/MonitorService.java @@ -47,6 +47,9 @@ import java.util.Date; import java.util.StringTokenizer; +import androidx.annotation.RequiresApi; +import androidx.core.app.NotificationCompat; + @SuppressLint("HandlerLeak") public class MonitorService extends Service { diff --git a/src/main/java/org/havenapp/main/service/SignalSender.java b/src/main/java/org/havenapp/main/service/SignalSender.java index da30cbb8..59b1848e 100644 --- a/src/main/java/org/havenapp/main/service/SignalSender.java +++ b/src/main/java/org/havenapp/main/service/SignalSender.java @@ -1,15 +1,17 @@ package org.havenapp.main.service; import android.content.Context; - import android.os.CountDownTimer; import android.telephony.SmsManager; import android.text.TextUtils; import android.util.Log; + import net.sourceforge.argparse4j.inf.Namespace; import org.asamk.signal.Main; import org.havenapp.main.PreferenceManager; +import org.havenapp.main.R; +import org.havenapp.main.Utils; import java.util.ArrayList; import java.util.HashMap; @@ -25,11 +27,23 @@ public class SignalSender { private static SignalSender mInstance; private String mUsername; //aka your signal phone number private CountDownTimer mCountdownTimer; + private PreferenceManager preferences; + private String messageString; + private String prefix; + private String suffix; + private int interval; + private int mAlertCount; private SignalSender(Context context, String username) { mContext = context; mUsername = username; + mAlertCount = 0; + preferences = new PreferenceManager(mContext); + prefix = preferences.getHearbeatPrefix(); + suffix = preferences.getHeartbeatSuffix(); + messageString = preferences.getHeartbeatMonitorMessage(); + interval = preferences.getHeartbeatNotificationTimeMs() / 60000; } public static synchronized SignalSender getInstance (Context context, String username) @@ -93,50 +107,75 @@ public void run() { public void stopHeartbeatTimer () { - mCountdownTimer.cancel(); - mCountdownTimer = null; - Log.d("HEARTBEAT TIMER", "Stopped" ); + mAlertCount = 0; + + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + Log.d("HEARTBEAT MONITOR", "Stopped" ); + } else + Log.d("HEARTBEAT MONITOR", "null"); + } public void startHeartbeatTimer (int countMs) { - if (countMs <= 10000) //Default if '0' setting + if (countMs <= 10000) countMs = 300000; mCountdownTimer = new CountDownTimer(countMs,1000) { - public void onTick(long millisUntilFinished) { - Log.d("HEARTBEAT TIMER"," seconds remaining: " + millisUntilFinished / 1000); + // Log.d("HEARTBEAT MONITOR," seconds remaining: " + millisUntilFinished / 1000); } - public void onFinish() { - Log.d("HEARTBEAT TIMER"," Done, update message sent!"); - beatingHeart(); + try { + beatingHeart(); + } catch(Throwable e) { + e.printStackTrace(); + } start(); } }.start(); } - private void beatingHeart () - { - PreferenceManager preferences = new PreferenceManager(mContext); + private void beatingHeart () { int unicodeBeat = 0x1F493; String emojiString = new String(Character.toChars(unicodeBeat)); + messageString = preferences.getHeartbeatMonitorMessage(); + + /** + * Use compiler for optimized concatenation. + * Send an explanatory message first, then the unicode symbol. + * Ensure above message sent before updating count. + * Check for a custom message, send that instead. + **/ + + if (mAlertCount < 1 ) + messageString = prefix + " " + interval + " " + suffix + "\n" + mContext.getString(R.string.battery_level_msg_text) + ": " + Utils.getBatteryPercentage(mContext) + "%"; + else if (messageString != null) + messageString = messageString + "\n" + mContext.getString(R.string.battery_level_msg_text) + ": " + Utils.getBatteryPercentage(mContext) + "%"; + else + messageString = emojiString + "\n" + mContext.getString(R.string.battery_level_msg_text) + ": " + Utils.getBatteryPercentage(mContext) + "%"; + + initHbMessage(messageString); + } + private void initHbMessage (String message) + { if (!TextUtils.isEmpty(mUsername)) { getInstance(mContext, mUsername.trim()); ArrayList recipient = new ArrayList<>(); recipient.add(preferences.getSmsNumber()); - sendMessage(recipient, emojiString,null); - } - else if (!TextUtils.isEmpty(preferences.getSmsNumber())) { - + sendMessage(recipient, message,null); + } else if (!TextUtils.isEmpty(preferences.getSmsNumber())) { SmsManager manager = SmsManager.getDefault(); - StringTokenizer st = new StringTokenizer(preferences.getSmsNumber(),","); while (st.hasMoreTokens()) - manager.sendTextMessage(st.nextToken(), null, emojiString, null, null); + manager.sendTextMessage(st.nextToken(), null, message, null, null); } + + mAlertCount ++; //moved outside of the send functions for now + Log.d("HEARTBEAT MONITOR", "Sent: " + message); } public void sendMessage (final ArrayList recipients, final String message, final String attachment) diff --git a/src/main/java/org/havenapp/main/service/WebServer.java b/src/main/java/org/havenapp/main/service/WebServer.java index a56255e3..fd749a76 100644 --- a/src/main/java/org/havenapp/main/service/WebServer.java +++ b/src/main/java/org/havenapp/main/service/WebServer.java @@ -6,8 +6,8 @@ import android.util.Log; import org.havenapp.main.R; -import org.havenapp.main.database.HavenEventDB; import org.havenapp.main.Utils; +import org.havenapp.main.database.HavenEventDB; import org.havenapp.main.model.Event; import org.havenapp.main.model.EventTrigger; import org.havenapp.main.resources.ResourceManager; diff --git a/src/main/java/org/havenapp/main/ui/EventTriggerAdapter.java b/src/main/java/org/havenapp/main/ui/EventTriggerAdapter.java index babdeb3c..40b113c8 100644 --- a/src/main/java/org/havenapp/main/ui/EventTriggerAdapter.java +++ b/src/main/java/org/havenapp/main/ui/EventTriggerAdapter.java @@ -23,7 +23,6 @@ import java.util.List; import androidx.annotation.NonNull; -import androidx.core.content.FileProvider; import androidx.recyclerview.widget.RecyclerView; import nl.changer.audiowife.AudioWife; diff --git a/src/main/res/layout/pref_dialog_edit_text.xml b/src/main/res/layout/pref_dialog_edit_text.xml index 1d7db805..8bf2b571 100644 --- a/src/main/res/layout/pref_dialog_edit_text.xml +++ b/src/main/res/layout/pref_dialog_edit_text.xml @@ -28,7 +28,8 @@ + android:layout_height="wrap_content" + android:singleLine="true" /> \ No newline at end of file diff --git a/src/main/res/layout/pref_dialog_edit_text_hint_signal.xml b/src/main/res/layout/pref_dialog_edit_text_hint_signal.xml index caccdf5f..69de752e 100644 --- a/src/main/res/layout/pref_dialog_edit_text_hint_signal.xml +++ b/src/main/res/layout/pref_dialog_edit_text_hint_signal.xml @@ -36,7 +36,8 @@ android:id="@android:id/edit" android:layout_width="match_parent" android:layout_height="wrap_content" - android:hint="@string/hint_number" /> + android:hint="@string/hint_number" + android:singleLine="true" /> \ No newline at end of file diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 1ac40f0b..348e99d6 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -140,7 +140,7 @@ Notification Time Interval Only send notifications at configured interval Enter time (minutes) to limit notifications. \'0\' to send every notification. - minutes(s) + minute(s) Keep Watch! Switch camera or use the slider to adjust motion detection sensitivity Disable Battery Optimizations @@ -150,11 +150,19 @@ Remove all logs Events deleted - Heartbeat Monitor - Enable Heartbeat Notifications - Monitor Time Interval - Enter interval time (minutes) to receive notifications:\n\nMinimum of 1, default is 5. - Set alert delay for the status notifications + Haven Heartbeat Monitor + Enable Heartbeat Alert + Checkup Interval + Enter time (minutes) to send battery % and a single-character heart emoji. Alerts cease when Haven stops monitoring for any reason. + Configure delay between alerts + Customize message sent for heartbeat notifications. Leave blank to use default heart emoji + Alert Message + Set custom message text + Custom alerts enabled + Heartbeat monitor activate: You will receive a notification every + minute(s) Haven is active & monitoring. + Battery Level + VideoPlayerActivity Storage Folder Path Where captured media is stored diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml index 78d85a9a..ed6db017 100644 --- a/src/main/res/values/styles.xml +++ b/src/main/res/values/styles.xml @@ -1,6 +1,5 @@ - +