Compare commits

..

24 commits
1.0 ... master

Author SHA1 Message Date
wesaphzt
0cfce130fd add lock stats 2019-09-22 16:12:49 +01:00
wesaphzt
1b0d587a8d minor code clean up 2019-09-22 16:12:21 +01:00
wesaphzt
995403a129 formatting 2019-09-22 13:38:19 +01:00
wesaphzt
0aa22e93e3 add changelog 2019-09-22 13:34:05 +01:00
wesaphzt
36bb398fd4 release 1.2 2019-09-20 13:06:13 +01:00
wesaphzt
6b560beac8 fix background service for < 8.0 2019-09-20 13:04:11 +01:00
wesaphzt
248a8eeb0b haptic feedback 2019-09-17 13:26:58 +01:00
wesaphzt
000eb550a2 fix links 2019-09-15 14:53:47 +01:00
wesaphzt
e51a510645 reworked animation logic 2019-09-14 16:39:18 +01:00
wesaphzt
18018360d3 check for admin 2019-09-11 22:45:25 +01:00
wesaphzt
1cc68f0fff add onActivityResult super 2019-09-11 22:43:45 +01:00
wesaphzt
063beba464 adjust constant run option slightly to prevent annoying artifact 2019-09-09 20:21:24 +01:00
wesaphzt
10db550988 boot update 2019-09-09 16:13:21 +01:00
wesaphzt
1b2a5139b9 version increase 2019-09-09 13:48:09 +01:00
wesaphzt
813b948f19 option to run locking functionality while phone is locked to force pin 2019-09-09 13:33:04 +01:00
wesaphzt
53828ddc3f fix to stop service correctly preventing mem leak & code cleanup 2019-09-08 20:00:33 +01:00
wesaphzt
4d67f4dd47 notification priority for nougat & < changed to low 2019-09-07 19:54:36 +01:00
wesaphzt
0a0079db37 intro slide changes 2019-09-07 16:09:45 +01:00
wesaphzt
87e349d02a animation scaling issues fixed 2019-09-07 16:00:32 +01:00
wesaphzt
cd8226cddc gradle update 2019-09-07 15:58:27 +01:00
wesaphzt
c2b6299102 Merge remote-tracking branch 'origin/master' 2019-07-04 10:16:51 +01:00
wesaphzt
480907063b Update gradle.properties 2019-07-04 10:16:15 +01:00
wesaphzt
785f8d3eac
Update README.md 2019-07-03 16:02:07 +00:00
wesaphzt
4fe08078e0
Update README.md 2019-07-03 15:52:27 +00:00
24 changed files with 631 additions and 237 deletions

116
.idea/codeStyles/Project.xml generated Normal file
View file

@ -0,0 +1,116 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="XML">
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
</code_scheme>
</component>

21
CHANGELOG.md Normal file
View file

@ -0,0 +1,21 @@
Changelog
==========
Release 1.2 *(2019-09-21)*
----------------------------
* Fix for background service < Android 8.0/Oreo
* Add option for haptic feedback (vibration) on lock trigger
* Reworked animation logic
* Fix 'License' and 'Bug report' links on about page
Release 1.1 *(2019-06-25)*
----------------------------
* Animation scaling issues fixed
* Stop service correctly to fix memory leak & reduce code
* Notification priority changed to low for Nougat and lower
* Option added to run service when screen is off to be able to force PIN entry
* Gradle & library updates
Release 1.0 *(2019-06-01)*
----------------------------
* Initial release

View file

@ -1,10 +1,9 @@
# Private Lock
<a href="https://github.com/wesaphzt/privatelock/releases/latest" alt="GitHub Release"><img src="https://img.shields.io/github/release/wesaphzt/privatelock.svg?logo=github"></a>
[![License](https://img.shields.io/github/license/wesaphzt/privatelock.svg)](LICENSE)
[![License](https://img.shields.io/github/license/wesaphzt/privatelock.svg?color=green)](LICENSE)
[<img alt="Get it on F-Droid" height="75" src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png">](https://f-droid.org/packages/com.wesaphzt.privatelock/)
[description]
A simple app to automatically lock your phone based on movement force, or the acceleration to be more accurate.
Private Lock can help protect your privacy and security by monitoring the accelerometer in the background and if the threshold is breached, lock the screen.

View file

@ -1,13 +1,13 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
compileSdkVersion 29
defaultConfig {
applicationId "com.wesaphzt.privatelock"
minSdkVersion 17
targetSdkVersion 28
versionCode 1
versionName "1.0"
targetSdkVersion 29
versionCode 3
versionName "1.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@ -22,10 +22,10 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.intuit.sdp:sdp-android:1.0.3'
implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.preference:preference:1.1.0'
implementation 'com.github.AppIntro:AppIntro:5.1.0'
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'

View file

@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<!--pre-oreo-->
<uses-permission android:name="android.permission.WAKE_LOCK" />

View file

@ -22,10 +22,11 @@ import androidx.fragment.app.FragmentTransaction;
import android.os.CountDownTimer;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewTreeObserver;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
@ -36,10 +37,11 @@ import com.wesaphzt.privatelock.fragments.FragmentAbout;
import com.wesaphzt.privatelock.fragments.FragmentDonate;
import com.wesaphzt.privatelock.fragments.FragmentSettings;
import com.wesaphzt.privatelock.receivers.DeviceAdminReceiver;
import com.wesaphzt.privatelock.receivers.PauseReceiver;
import com.wesaphzt.privatelock.service.LockService;
import com.wesaphzt.privatelock.widget.LockWidgetProvider;
import java.util.Locale;
import static com.wesaphzt.privatelock.service.LockService.CHANNEL_ID;
import static com.wesaphzt.privatelock.service.LockService.DEFAULT_SENSITIVITY;
import static com.wesaphzt.privatelock.service.LockService.activeListener;
@ -54,7 +56,6 @@ public class MainActivity extends AppCompatActivity {
private boolean mInitialized;
private static SensorManager mSensorManager;
private Sensor mAccelerometer;
private final float NOISE = (float) 2.0;
private SensorEventListener mActiveListener;
@ -70,22 +71,26 @@ public class MainActivity extends AppCompatActivity {
public static final String PREFS_THRESHOLD = "THRESHOLD";
private CountDownTimer cdTimer;
private final int cdTimerLength = 2000;
private final int cdTimerLength = 1500;
private boolean isRunning = false;
private boolean isHit = false;
//stats
private TextView tvLastBreachValue;
private TextView tvAvgBreachValue;
private TextView tvHighestBreachValue;
private int triggerCount = 0;
private float avgBreachValueTotal = 0;
private double highestBreach = 0;
private Circle circle;
private Circle circle_bg;
//circle bg color
private int circleBgR = 240; private int circleBgG = 240; private int circleBgB = 240;
//circle color
private int circleDefaultR = 88; private int circleDefaultG = 186; private int circleDefaultB = 255;
//circle lock color
private int circleLockR = 88; private int circleLockG = 255; private int circleLockB = 135;
int animationDuration = 220;
//first run
final private String PREF_VERSION_CODE_KEY = "VERSION_CODE";
final private int DOESNT_EXIST = -1;
CircleAngleAnimation animation;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -126,19 +131,49 @@ public class MainActivity extends AppCompatActivity {
}
});
//https://stackoverflow.com/questions/29381474/how-to-draw-a-circle-with-animation-in-android-with-circle-size-based-on-a-value
//animation
circle = findViewById(R.id.circle);
circle_bg = findViewById(R.id.circle_bg);
final RelativeLayout relativeLayout = findViewById(R.id.content_main);
final RelativeLayout rlCircle = findViewById(R.id.rlCircle);
//scale height/width of animation
relativeLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//only want to do this once
relativeLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
circle.setRect((circle.getHeight() / 2), (circle.getHeight()) / 2);
circle_bg.setRect((circle_bg.getHeight() / 2), (circle_bg.getHeight()) / 2);
circle.setX((rlCircle.getWidth() - circle.getRect()) / 2);
circle_bg.setX((rlCircle.getWidth() - circle.getRect()) / 2);
}
});
circle.setColor(circleDefaultR, circleDefaultG, circleDefaultB);
//set background circle
CircleAngleAnimation animation = new CircleAngleAnimation(circle_bg, 360);
//initial animation
animation.setDuration(500);
circle_bg.setColor(circleBgR,circleBgG,circleBgB);
//circle bg color
int circleBgR = 240;
int circleBgG = 240;
int circleBgB = 240;
circle_bg.setColor(circleBgR, circleBgG, circleBgB);
circle_bg.startAnimation(animation);
//stats
tvLastBreachValue = findViewById(R.id.tvLastBreachValue);
tvAvgBreachValue = findViewById(R.id.tvAvgBreachValue);
tvHighestBreachValue = findViewById(R.id.tvHighestBreachValue);
//shared prefs
try {
mSensitivity = prefs.getInt(PREFS_THRESHOLD, DEFAULT_SENSITIVITY);
@ -148,12 +183,19 @@ public class MainActivity extends AppCompatActivity {
//timer when lock hit
cdTimer = new CountDownTimer(cdTimerLength, 1000) {
public void onTick(long millisUntilFinished) {
isRunning = true;
isHit = true;
}
public void onFinish() {
isRunning = false;
isHit = false;
circle.setColor(circleDefaultR, circleDefaultG, circleDefaultB);
//reset stat variables
triggerCount = 0;
avgBreachValueTotal = 0;
highestBreach = 0;
}
};
@ -222,6 +264,7 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//launch service if permission granted
if (requestCode == REQUEST_CODE_ENABLE_ADMIN) {
if(resultCode == Activity.RESULT_OK) {
@ -270,27 +313,12 @@ public class MainActivity extends AppCompatActivity {
private void startServicePrep() {
//stop this listener
mSensorManager.unregisterListener(mActiveListener);
Intent intent = new Intent(context, LockService.class);
try {
//stop any already running service
LockService.mSensorManager.unregisterListener(LockService.activeListener);
startLockService(intent);
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
lockWidgetProvider.setWidgetStart(context);
//start service intent
Intent startIntent = new Intent(context, LockService.class);
startIntent.setAction(LockService.ACTION_START_FOREGROUND_SERVICE);
//cancel any pause timer that might be running
try {
PauseReceiver.mCountdown.cancel();
} catch (Exception e) {
e.printStackTrace();
}
} catch (Exception e) {
startLockService(intent);
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
lockWidgetProvider.setWidgetStart(context);
}
startLockService(startIntent);
}
@Override
@ -376,7 +404,10 @@ public class MainActivity extends AppCompatActivity {
//get current version code
int currentVersionCode = BuildConfig.VERSION_CODE;
//get saved version code
int DOESNT_EXIST = -1;
int savedVersionCode = DOESNT_EXIST;
//first run
String PREF_VERSION_CODE_KEY = "VERSION_CODE";
try {
savedVersionCode = this.prefs.getInt(PREF_VERSION_CODE_KEY, DOESNT_EXIST);
} catch (Exception e) {
@ -411,6 +442,7 @@ public class MainActivity extends AppCompatActivity {
float deltaY = Math.abs(mLastY - y);
float deltaZ = Math.abs(mLastZ - z);
float NOISE = (float) 2.0;
if (deltaX < NOISE) deltaX = (float) 0.0;
if (deltaY < NOISE) deltaY = (float) 0.0;
if (deltaZ < NOISE) deltaZ = (float) 0.0;
@ -419,35 +451,59 @@ public class MainActivity extends AppCompatActivity {
mLastY = y;
mLastZ = z;
float total = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
float total = (float) Math.sqrt((deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ));
int calculatedAngleInt;
int calculatedAngleInt = 0;
if (total <= mSensitivity) {
//do nothing if timer currently running
if (total >= mSensitivity) {
//lock screen threshold hit
stats(total);
if(!isHit) {
CircleAngleAnimation anim = new CircleAngleAnimation(circle, 360);
//circle lock color
int circleLockR = 88;
int circleLockG = 255;
int circleLockB = 135;
circle.setColor(circleLockR, circleLockG, circleLockB);
anim.setDuration(animationDuration);
//set lock color
circle.startAnimation(anim);
isHit = true;
cdTimer.start();
} else {
if(!isRunning) {
isRunning = true;
}
}
} else {
if(isRunning)
return;
if(isHit)
return;
calculatedAngleInt = Math.round((total / mSensitivity) * 360);
CircleAngleAnimation animation = new CircleAngleAnimation(circle, calculatedAngleInt);
animation = new CircleAngleAnimation(circle, calculatedAngleInt);
animation.setDuration(animationDuration);
circle.startAnimation(animation);
} else if (total > mSensitivity) {
//lock screen threshold hit
if(isRunning)
//do nothing if timer currently running
return;
CircleAngleAnimation animation = new CircleAngleAnimation(circle, 360);
animation.setDuration(animationDuration);
//set lock color
circle.setColor(circleLockR, circleLockG, circleLockB);
circle.startAnimation(animation);
cdTimer.start();
}
}
}
private void stats(float total) {
tvLastBreachValue.setText(String.format(Locale.ENGLISH, "%.1f", (double) total));
if(total == 0 || total > highestBreach) {
highestBreach = total;
}
tvHighestBreachValue.setText(String.format(Locale.ENGLISH, "%.1f", highestBreach));
triggerCount += 1;
avgBreachValueTotal += total;
tvAvgBreachValue.setText(String.format(Locale.ENGLISH, "%.1f", avgBreachValueTotal / triggerCount));
}
}

View file

@ -13,15 +13,14 @@ public class Circle extends View {
private static final int START_ANGLE_POINT = 90;
private final Paint paint;
private final RectF rect;
private RectF rect;
private float angle;
private final int strokeWidth = 10;
public Circle(Context context, AttributeSet attrs) {
super(context, attrs);
final int strokeWidth = 10;
paint = new Paint();
paint.setAntiAlias(true);
paint.setStyle(Paint.Style.FILL);
@ -29,8 +28,8 @@ public class Circle extends View {
//circle color (currently set upon instance)
//paint.setColor(Color.BLUE);
//size
rect = new RectF(strokeWidth, strokeWidth, 600 + strokeWidth, 600 + strokeWidth);
//size (currently set upon instance)
//rect = new RectF(strokeWidth, strokeWidth, 230 + strokeWidth, 230 + strokeWidth);
//initial angle (optional)
angle = 0;
@ -53,4 +52,12 @@ public class Circle extends View {
public void setAngle(float angle) {
this.angle = angle;
}
public void setRect(int right, int bottom) {
this.rect = new RectF(strokeWidth, strokeWidth, right, bottom);
}
public float getRect() {
return rect.right;
}
}

View file

@ -21,9 +21,8 @@ import com.wesaphzt.privatelock.R;
public class FragmentAbout extends Fragment {
private static String GITHUB_URI;
private static final String LICENSE_URI = GITHUB_URI + "/blob/master/LICENSE.txt";
private static final String BUG_REPORT_URI = GITHUB_URI + "/issues";
private static String LICENSE_URI;
private static String BUG_REPORT_URI;
private static String AUTHOR_GITHUB;
@Nullable
@ -32,6 +31,8 @@ public class FragmentAbout extends Fragment {
View v = inflater.inflate(R.layout.fragment_about, container, false);
GITHUB_URI = getString(R.string.app_github);
LICENSE_URI = GITHUB_URI + "/blob/master/LICENSE";
BUG_REPORT_URI = GITHUB_URI + "/issues";
AUTHOR_GITHUB = getString(R.string.app_github_dev);
String versionName = "";

View file

@ -7,7 +7,9 @@ import androidx.annotation.Nullable;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
import androidx.preference.CheckBoxPreference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
@ -15,17 +17,26 @@ import com.wesaphzt.privatelock.R;
public class FragmentSettings extends PreferenceFragmentCompat {
private SharedPreferences prefs;
private Context context;
private CheckBoxPreference cbRunConstant;
private SharedPreferences sharedPreferences;
private SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener;
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
setHasOptionsMenu(true);
Context context = getContext();
context = getContext();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
//this static call will reset default values only on the first read
PreferenceManager.setDefaultValues(context, R.xml.preferences, false);
cbRunConstant = (CheckBoxPreference) findPreference("RUN_CONSTANT");
}
@Override
@ -33,6 +44,24 @@ public class FragmentSettings extends PreferenceFragmentCompat {
super.onCreate(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
@Override
public void onDestroy() {
super.onDestroy();
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
@Override
public void onPause() {
super.onPause();
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@ -41,6 +70,16 @@ public class FragmentSettings extends PreferenceFragmentCompat {
//bg color
view.setBackgroundColor(getResources().getColor(R.color.white));
sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if(key.equals("RUN_CONSTANT") && cbRunConstant.isChecked()) {
Toast.makeText(context, getString(R.string.settings_restart_service_toast), Toast.LENGTH_LONG).show();
}
}
};
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
}
@Override

View file

@ -8,7 +8,6 @@ import android.os.Build;
import android.preference.PreferenceManager;
import com.wesaphzt.privatelock.service.LockService;
import com.wesaphzt.privatelock.widget.LockWidgetProvider;
public class BootReceiver extends BroadcastReceiver {
@ -16,19 +15,16 @@ public class BootReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if(prefs.getBoolean("START_ON_BOOT", false)) {
Intent i = new Intent(context, LockService.class);
Intent startIntent = new Intent(context, LockService.class);
startIntent.setAction(LockService.ACTION_START_FOREGROUND_SERVICE);
//check android api
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(i);
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
lockWidgetProvider.setWidgetStart(context);
context.startForegroundService(startIntent);
} else {
context.startService(i);
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
lockWidgetProvider.setWidgetStart(context);
context.startService(startIntent);
}
}
}

View file

@ -1,20 +1,11 @@
package com.wesaphzt.privatelock.receivers;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.preference.PreferenceManager;
import com.wesaphzt.privatelock.service.LockService;
import com.wesaphzt.privatelock.widget.LockWidgetProvider;
import com.wesaphzt.privatelock.R;
import static com.wesaphzt.privatelock.service.LockService.activeListener;
import static com.wesaphzt.privatelock.service.LockService.mSensorManager;
import static com.wesaphzt.privatelock.service.LockService.disabled;
public class NotificationReceiver extends BroadcastReceiver {
@ -23,37 +14,13 @@ public class NotificationReceiver extends BroadcastReceiver {
String action = intent.getStringExtra("lock_service");
if (action.equals("lock_service_notification")) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
Intent stopIntent = new Intent(context, LockService.class);
stopIntent.setAction(LockService.ACTION_STOP_FOREGROUND_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String id = context.getString(R.string.notification_main_channel_id);
notificationManager.deleteNotificationChannel(id);
if(PauseReceiver.isRunning) {
PauseReceiver.mCountdown.cancel(); PauseReceiver.isRunning = false;
disabled = true;
mSensorManager.unregisterListener(activeListener);
lockWidgetProvider.setWidgetStop(context);
context.startForegroundService(stopIntent);
} else {
disabled = true;
mSensorManager.unregisterListener(activeListener);
lockWidgetProvider.setWidgetStop(context);
}
} else {
notificationManager.cancel(LockService.NOTIFICATION_ID);
if(PauseReceiver.isRunning) {
PauseReceiver.mCountdown.cancel(); PauseReceiver.isRunning = false;
disabled = true;
mSensorManager.unregisterListener(activeListener);
lockWidgetProvider.setWidgetStop(context);
} else {
disabled = true;
mSensorManager.unregisterListener(activeListener);
lockWidgetProvider.setWidgetStop(context);
}
context.startService(stopIntent);
}
}
}

View file

@ -3,6 +3,8 @@ package com.wesaphzt.privatelock.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import static com.wesaphzt.privatelock.service.LockService.disabled;
import static com.wesaphzt.privatelock.service.LockService.mInitialized;
@ -11,6 +13,8 @@ public class PresenceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
//prevent lock animation artifacts
mInitialized = false;
@ -18,7 +22,9 @@ public class PresenceReceiver extends BroadcastReceiver {
disabled = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
if(! prefs.getBoolean("RUN_CONSTANT", false)) {
disabled = true;
}
}
}
}

View file

@ -15,12 +15,15 @@ import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.CountDownTimer;
import android.os.IBinder;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.app.NotificationCompat;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import android.widget.Toast;
@ -30,7 +33,11 @@ import com.wesaphzt.privatelock.receivers.DeviceAdminReceiver;
import com.wesaphzt.privatelock.receivers.NotificationReceiver;
import com.wesaphzt.privatelock.receivers.PauseReceiver;
import com.wesaphzt.privatelock.receivers.PresenceReceiver;
import com.wesaphzt.privatelock.widget.LockWidgetProvider;
import java.util.Objects;
import static androidx.core.app.NotificationCompat.PRIORITY_LOW;
import static androidx.core.app.NotificationCompat.PRIORITY_MIN;
public class LockService extends JobIntentService {
@ -40,7 +47,6 @@ public class LockService extends JobIntentService {
private float mLastX, mLastY, mLastZ;
public static boolean mInitialized;
public static SensorManager mSensorManager;
private final float NOISE = (float) 2.0;
public static Sensor mAccelerometer;
public static SensorEventListener activeListener;
@ -66,24 +72,42 @@ public class LockService extends JobIntentService {
public static final int DEFAULT_SENSITIVITY = 10;
public static int SENSITIVITY;
public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";
public static final String ACTION_START_FOREGROUND_SERVICE = "ACTION_START_FOREGROUND_SERVICE";
PresenceReceiver presenceReceiver;
//check to stop multiple triggers
boolean isHit = false;
//vibrate
boolean isHaptic = false;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
context = getApplicationContext();
CHANNEL_ID = getString(R.string.notification_main_channel_id);
CHANNEL_NAME = getString(R.string.notification_main_channel_name);
//------------------------------------------------------------------------------------------
PresenceReceiver presenceReceiver = new PresenceReceiver();
if (intent != null) {
String action = intent.getAction();
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
assert action != null;
switch (action) {
case ACTION_START_FOREGROUND_SERVICE:
presenceReceiver = new PresenceReceiver();
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_USER_PRESENT);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(presenceReceiver, intentFilter);
//------------------------------------------------------------------------------------------
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
try {
SENSITIVITY = prefs.getInt(MainActivity.PREFS_THRESHOLD, DEFAULT_SENSITIVITY);
} catch (Exception e) {
Toast.makeText(context, "Unable to retrieve threshold", Toast.LENGTH_LONG).show();
}
//------------------------------------------------------------------------------------------
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
@ -106,15 +130,57 @@ public class LockService extends JobIntentService {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//create foreground service
startForeground(NOTIFICATION_ID, notification);
lockWidgetProvider.setWidgetStart(context);
disabled = false;
} else {
notificationManager.notify(NOTIFICATION_ID, notification);
lockWidgetProvider.setWidgetStart(context);
disabled = false;
}
//------------------------------------------------------------------------------------------
return LockService.START_STICKY;
break;
case ACTION_STOP_FOREGROUND_SERVICE:
try {
mSensorManager.unregisterListener(activeListener);
} catch (Exception e) {
e.printStackTrace();
}
unregisterReceiver(presenceReceiver);
disabled = true;
mInitialized = false;
if (PauseReceiver.isRunning) {
PauseReceiver.mCountdown.cancel();
PauseReceiver.isRunning = false;
}
try {
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
String id = context.getString(R.string.notification_main_channel_id);
notificationManager.deleteNotificationChannel(id);
} else {
notificationManager.cancel(LockService.NOTIFICATION_ID);
}
} catch (Exception e) {
e.printStackTrace();
}
lockWidgetProvider.setWidgetStop(context);
stopService(intent);
break;
}
} else {
return LockService.START_REDELIVER_INTENT;
}
return LockService.START_REDELIVER_INTENT;
}
@Override
@ -125,6 +191,11 @@ public class LockService extends JobIntentService {
@Override
protected void onHandleWork(@NonNull Intent intent) { }
@Override
public void onDestroy() {
super.onDestroy();
}
private void setSensorListener() {
activeListener = new SensorEventListener() {
@Override
@ -132,6 +203,11 @@ public class LockService extends JobIntentService {
if(LockService.disabled)
return;
//check prefs here so options can be changed without service restart
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
isHaptic = prefs.getBoolean("HAPTIC_FEEDBACK", false);
sensorCalc(event);
}
@ -156,6 +232,7 @@ public class LockService extends JobIntentService {
float deltaY = Math.abs(mLastY - y);
float deltaZ = Math.abs(mLastZ - z);
float NOISE = (float) 2.0;
if (deltaX < NOISE) deltaX = (float) 0.0;
if (deltaY < NOISE) deltaY = (float) 0.0;
if (deltaZ < NOISE) deltaZ = (float) 0.0;
@ -164,18 +241,56 @@ public class LockService extends JobIntentService {
mLastY = y;
mLastZ = z;
float total = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
float total = (float) Math.sqrt((deltaX * deltaX) + (deltaY * deltaY) + (deltaZ * deltaZ));
if (total > SENSITIVITY) {
try {
if (isActiveAdmin()) {
if(!isHaptic) {
mDPM.lockNow();
} else { //if haptic
if(!isHit) { //run if not triggered yet
isHit = true;
mDPM.lockNow();
vibrateItBaby();
//stop multiple haptic triggers in a row
new CountDownTimer(1000, 1000) {
public void onTick(long millisUntilFinished) {
isHit = true;
}
public void onFinish() {
isHit = false;
}
}.start();
}
}
} else {
Toast.makeText(context, "Device admin not enabled", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Toast.makeText(context, "Error locking, does app have device admin permissions?", Toast.LENGTH_SHORT).show();
Toast.makeText(context, "Unknown locking error", Toast.LENGTH_SHORT).show();
}
}
}
}
private void vibrateItBaby() {
int vibrateTime = 100;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
((Vibrator) Objects.requireNonNull(getSystemService(VIBRATOR_SERVICE))).vibrate(VibrationEffect.createOneShot(vibrateTime, VibrationEffect.DEFAULT_AMPLITUDE));
} else {
((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(vibrateTime);
}
}
private boolean isActiveAdmin() {
return mDPM.isAdminActive(mDeviceAdmin);
}
private void setNotification() {
//notification
pendingIntent = PendingIntent.getActivity(context, 0,
@ -206,6 +321,7 @@ public class LockService extends JobIntentService {
.setTicker(getString(R.string.app_name) + " is running")
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "STOP", pendingCloseIntent)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "PAUSE", pendingPauseIntent)
.setPriority(PRIORITY_LOW)
.setOngoing(true)
.build();
@ -221,6 +337,7 @@ public class LockService extends JobIntentService {
.setTicker(getString(R.string.app_name) + " is running")
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "STOP", pendingCloseIntent)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "PAUSE", pendingPauseIntent)
.setPriority(PRIORITY_LOW)
.setOngoing(true)
.build();
}

View file

@ -1,6 +1,5 @@
package com.wesaphzt.privatelock.widget;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@ -14,12 +13,6 @@ import android.widget.RemoteViews;
import com.wesaphzt.privatelock.service.LockService;
import com.wesaphzt.privatelock.R;
import com.wesaphzt.privatelock.receivers.PauseReceiver;
import static com.wesaphzt.privatelock.service.LockService.CHANNEL_ID;
import static com.wesaphzt.privatelock.service.LockService.activeListener;
import static com.wesaphzt.privatelock.service.LockService.disabled;
import static com.wesaphzt.privatelock.service.LockService.mSensorManager;
public class LockWidgetProvider extends AppWidgetProvider {
@ -72,33 +65,14 @@ public class LockWidgetProvider extends AppWidgetProvider {
editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
editor.apply();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent stopIntent = new Intent(context, LockService.class);
stopIntent.setAction(LockService.ACTION_STOP_FOREGROUND_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notificationManager.deleteNotificationChannel(CHANNEL_ID);
//if countdown timer is running (pause), cancel
if(PauseReceiver.isRunning) {
PauseReceiver.mCountdown.cancel(); PauseReceiver.isRunning = false;
disabled = true;
mSensorManager.unregisterListener(activeListener);
setWidgetStop(context);
context.startForegroundService(stopIntent);
} else {
disabled = true;
mSensorManager.unregisterListener(activeListener);
setWidgetStop(context);
}
} else {
notificationManager.cancel(LockService.NOTIFICATION_ID);
if(PauseReceiver.isRunning) {
PauseReceiver.mCountdown.cancel(); PauseReceiver.isRunning = false;
disabled = true;
mSensorManager.unregisterListener(activeListener);
setWidgetStop(context);
} else {
disabled = true;
mSensorManager.unregisterListener(activeListener);
setWidgetStop(context);
}
context.startService(stopIntent);
}
//if service is not running
@ -106,15 +80,13 @@ public class LockWidgetProvider extends AppWidgetProvider {
editor.putBoolean(context.getString(R.string.widget_prefs_service_id), true);
editor.commit();
Intent i = new Intent(context, LockService.class);
Intent startIntent = new Intent(context, LockService.class);
startIntent.setAction(LockService.ACTION_START_FOREGROUND_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
disabled = false;
context.startForegroundService(i);
setWidgetStart(context);
context.startForegroundService(startIntent);
} else {
disabled = false;
context.startService(i);
setWidgetStart(context);
context.startService(startIntent);
}
}
}

View file

@ -1,24 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="200dp"
android:viewportWidth="300"
android:viewportHeight="300">
<path
android:pathData="M150,150m-150,0a150,150 0,1 1,300 0a150,150 0,1 1,-300 0"
android:fillColor="#80e5ff"/>
<path
android:pathData="M150.56,0.01V300c82.587,-0.3 149.44,-67.335 149.44,-149.99 0,-82.657 -66.858,-149.69 -149.44,-149.99z"
android:fillColor="#aaeeff"/>
<path
android:pathData="m281.15,222.37c-33.736,-8.65 -75.566,-13.771 -120.88,-13.771 -54.476,0 -103.92,7.404 -140.32,19.445 26.154,43.955 74.127,73.412 128.99,73.412 57.19,0 106.9,-32.009 132.2,-79.086z"
android:fillColor="#57bd84"/>
<path
android:pathData="m160.28,208.6c-3.615,0 -7.205,0.035 -10.774,0.1v92.748c1.396,-0.005 2.786,-0.03 4.173,-0.073 0.654,-0.02 1.305,-0.052 1.957,-0.081 0.92,-0.04 1.84,-0.088 2.756,-0.145 0.674,-0.042 1.348,-0.084 2.018,-0.135 1.092,-0.082 2.178,-0.18 3.26,-0.285 0.789,-0.077 1.576,-0.16 2.361,-0.25 1.053,-0.119 2.104,-0.245 3.148,-0.387 0.658,-0.089 1.314,-0.185 1.971,-0.282 0.906,-0.134 1.809,-0.278 2.709,-0.429 0.613,-0.103 1.227,-0.2 1.838,-0.311 1.369,-0.246 2.732,-0.51 4.09,-0.793 0.568,-0.119 1.131,-0.25 1.697,-0.375 0.922,-0.204 1.842,-0.414 2.756,-0.635 0.621,-0.149 1.24,-0.302 1.857,-0.459 0.98,-0.25 1.955,-0.513 2.93,-0.781 0.498,-0.138 0.998,-0.269 1.494,-0.412 1.313,-0.378 2.617,-0.776 3.914,-1.189 0.564,-0.179 1.123,-0.366 1.684,-0.552 0.902,-0.299 1.801,-0.605 2.695,-0.921 0.541,-0.19 1.084,-0.379 1.621,-0.576 1.316,-0.48 2.627,-0.975 3.924,-1.491 0.387,-0.153 0.768,-0.317 1.154,-0.475 1.004,-0.409 2.006,-0.828 2.998,-1.259 0.512,-0.221 1.021,-0.446 1.529,-0.673 0.961,-0.43 1.916,-0.869 2.867,-1.318 0.4,-0.188 0.803,-0.372 1.199,-0.563 1.283,-0.62 2.555,-1.259 3.818,-1.914 0.406,-0.21 0.807,-0.428 1.211,-0.643 0.943,-0.501 1.883,-1.011 2.814,-1.531 0.426,-0.237 0.852,-0.475 1.273,-0.716 1.205,-0.688 2.402,-1.388 3.586,-2.107 0.111,-0.068 0.225,-0.136 0.336,-0.204 1.219,-0.747 2.424,-1.516 3.621,-2.296 0.365,-0.237 0.729,-0.479 1.092,-0.721 0.963,-0.641 1.92,-1.292 2.867,-1.954 0.295,-0.207 0.594,-0.41 0.889,-0.618 1.213,-0.861 2.414,-1.737 3.602,-2.634 0.199,-0.15 0.396,-0.307 0.596,-0.458 1.012,-0.771 2.012,-1.555 3.002,-2.352 0.295,-0.236 0.59,-0.474 0.883,-0.713 1.088,-0.888 2.166,-1.787 3.229,-2.705 0.07,-0.061 0.143,-0.118 0.211,-0.179 1.16,-1.006 2.303,-2.032 3.434,-3.073 0.211,-0.194 0.418,-0.393 0.629,-0.588 0.949,-0.886 1.889,-1.783 2.814,-2.693 0.195,-0.19 0.391,-0.381 0.586,-0.572 2.191,-2.176 4.316,-4.419 6.371,-6.726 0.178,-0.199 0.354,-0.4 0.531,-0.601 0.963,-1.092 1.912,-2.195 2.842,-3.315 0.051,-0.061 0.104,-0.121 0.154,-0.182 1.021,-1.232 2.023,-2.483 3.006,-3.749 0.074,-0.095 0.146,-0.191 0.219,-0.287 0.889,-1.15 1.76,-2.314 2.615,-3.491 0.123,-0.17 0.248,-0.339 0.371,-0.51 1.848,-2.563 3.615,-5.187 5.303,-7.867 0.094,-0.15 0.186,-0.301 0.279,-0.451 0.793,-1.27 1.568,-2.551 2.322,-3.845 0.047,-0.08 0.096,-0.159 0.143,-0.24 0.822,-1.416 1.623,-2.847 2.4,-4.292 -33.736,-8.65 -75.566,-13.771 -120.88,-13.771z"
android:fillColor="#67c18c"/>
<path
android:pathData="M151.859,35.355C124.259,35.355 101.859,57.755 101.859,85.355L101.859,105.355L91.859,105.355C80.859,105.355 71.859,114.355 71.859,125.355L71.859,225.355C71.859,236.355 80.859,245.355 91.859,245.355L151.859,245.355L151.859,195.355C140.859,195.355 131.859,186.355 131.859,175.355C131.859,164.355 140.859,155.355 151.859,155.355L151.859,105.355L120.859,105.355L120.859,85.355C120.859,68.255 134.759,54.355 151.859,54.355Z"
android:fillColor="#0066ff"/>
<path
android:pathData="M150.58,35.415C178.18,35.415 200.58,57.815 200.58,85.415L200.58,105.415L210.58,105.415C221.58,105.415 230.58,114.415 230.58,125.415L230.58,225.415C230.58,236.415 221.58,245.415 210.58,245.415L150.58,245.415L150.58,195.415C161.58,195.415 170.58,186.415 170.58,175.415C170.58,164.415 161.58,155.415 150.58,155.415L150.58,105.415L181.58,105.415L181.58,85.415C181.58,68.315 167.68,54.415 150.58,54.415Z"
android:fillColor="#2A7FFF"/>
<vector android:height="200dp" android:viewportHeight="79.375"
android:viewportWidth="79.375" android:width="200dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#131313" android:pathData="M-0,0l79.375,0l0,79.375l-79.375,0z"/>
<path android:fillColor="#6F6F6F" android:fillType="evenOdd" android:pathData="M39.4592,8.6879C30.4924,13.067 20.4094,16.6195 12.1658,16.6777C17.2289,47.9896 20.134,60.0895 39.4592,69.9947C58.7851,60.09 61.6902,47.9896 66.7528,16.6777C58.5092,16.6195 48.4262,13.067 39.4592,8.6879Z"/>
<path android:fillAlpha="0.44" android:fillColor="#FF000000"
android:fillType="evenOdd" android:pathData="M39.4592,8.6863L39.4592,39.3406L62.4726,39.3406C64.0157,33.1047 65.2957,25.6905 66.7533,16.6764C58.5099,16.6182 48.4269,13.0659 39.4599,8.6868ZM39.4592,39.3406L16.446,39.3406C20.2631,54.7669 25.6966,62.9399 39.4592,69.9931Z"/>
<path android:fillColor="#DADADA" android:pathData="M39.9082,14.3248C34.5972,14.3248 30.2874,18.6351 30.2874,23.9461L30.2874,27.7945L28.3628,27.7945C26.2461,27.7945 24.5144,29.5264 24.5144,31.6431L24.5144,50.8855C24.5144,53.0021 26.2461,54.7338 28.3628,54.7338L39.9082,54.7338L39.9082,45.1128C37.7918,45.1128 36.0598,43.3808 36.0598,41.2642C36.0598,39.1477 37.7918,37.4158 39.9082,37.4158L39.9082,27.7945L33.9431,27.7945L33.9431,23.9461C33.9431,20.6558 36.6181,17.9811 39.9082,17.9811Z"/>
<path android:fillColor="#FFFFFF" android:pathData="M39.4697,14.3365C44.7805,14.3365 49.0908,18.6468 49.0908,23.9578L49.0908,27.8064L51.0151,27.8064C53.1318,27.8064 54.8635,29.5381 54.8635,31.6548L54.8635,50.8968C54.8635,53.0138 53.1318,54.7455 51.0151,54.7455L39.4697,54.7455L39.4697,45.1242C41.5864,45.1242 43.3181,43.3925 43.3181,41.2758C43.3181,39.1591 41.5864,37.4274 39.4697,37.4274L39.4697,27.8064L45.4348,27.8064L45.4348,23.9578C45.4348,20.6671 42.7601,17.9927 39.4697,17.9927Z"/>
<path android:fillColor="#131313" android:pathData="M39.6663,41.2731m-3.8293,0a3.8293,3.8293 0,1 1,7.6586 0a3.8293,3.8293 0,1 1,-7.6586 0"/>
</vector>

View file

@ -143,21 +143,96 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rlStatTitles"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_margin"
android:layout_marginTop="@dimen/activity_margin_small"
android:layout_marginEnd="@dimen/activity_margin">
<TextView
android:id="@+id/tvLastBreachValueTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_last_breach_value_title"
android:textSize="@dimen/_10sdp" />
<TextView
android:id="@+id/tvAvgBreachValueTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvLastBreachValueTitle"
android:text="@string/stats_avg_breach_value_title"
android:textSize="@dimen/_10sdp" />
<TextView
android:id="@+id/tvHighestBreachValueTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvAvgBreachValueTitle"
android:text="@string/stats_highest_breach_value_title"
android:textSize="@dimen/_10sdp" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rlStatValues"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/activity_margin"
android:layout_marginTop="@dimen/activity_margin_small"
android:layout_marginEnd="@dimen/activity_margin"
android:layout_toEndOf="@id/rlStatTitles">
<TextView
android:id="@+id/tvLastBreachValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_zero"
android:textSize="@dimen/_10sdp" />
<TextView
android:id="@+id/tvAvgBreachValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvLastBreachValue"
android:text="@string/stats_zero"
android:textSize="@dimen/_10sdp" />
<TextView
android:id="@+id/tvHighestBreachValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tvAvgBreachValue"
android:text="@string/stats_zero"
android:textSize="@dimen/_10sdp" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/rlCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/activity_margin_large"
android:layout_gravity="center_horizontal">
<com.wesaphzt.privatelock.animation.Circle
android:id="@+id/circle_bg"
android:layout_width="240dp"
android:layout_height="240dp"
android:layout_centerHorizontal="true" />
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal" />
<com.wesaphzt.privatelock.animation.Circle
android:id="@+id/circle"
android:layout_width="240dp"
android:layout_height="240dp"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal" />
</RelativeLayout>

View file

@ -15,13 +15,20 @@
<string name="main_lock_sensitivity_title_arrow"></string>
<string name="sensitivity_value">Value: %1$s</string>
<!--stats-->
<string name="stats_last_breach_value_title">Last Breach Value:</string>
<string name="stats_avg_breach_value_title">Avg. Breach Value:</string>
<string name="stats_highest_breach_value_title">Highest Breach Value:</string>
<string name="stats_zero">0</string>
<!--intro-->
<string name="slider_page_one_title">Private Lock</string>
<string name="slider_page_one_title">@string/app_name</string>
<string name="slider_page_one_desc">Private Lock, the perfect companion to help protect your phone privacy and security.</string>
<string name="slider_page_two_title">Protect against theft</string>
<string name="slider_page_two_title">Protect Against Theft</string>
<string name="slider_page_two_desc">If someone takes your phone while you\'re using it, your phone is unlocked and all your private data is up for grabs.</string>
<string name="slider_page_three_title">Always running</string>
<string name="slider_page_three_desc">Should something happen, your phone will be quickly locked, dependent on the sensitivity you\'ve set.</string>
<string name="slider_page_three_title">Always Running</string>
<string name="slider_page_three_desc">Should something happen, your phone will be quickly locked, dependent on the sensitivity you\'ve set.
\n\nDon\'t forget to disable battery optimization!</string>
<!--actionbar-->
<string name="action_start">Start</string>
@ -61,6 +68,9 @@
<string name="about_bug_report_image_desc">Bug report image</string>
<!--message-->
<string name="settings_restart_service_toast">If service is running, restart for setting to take effect.</string>
<!--donate-->
<string name="donate_bitcoin_image_desc">Bitcoin image</string>
<string name="donate_litecoin_image_desc">Litecoin image</string>

View file

@ -2,20 +2,31 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="Lock Service">
<CheckBoxPreference
android:defaultValue="false"
android:key="START_ON_BOOT"
android:title="System start" />
<CheckBoxPreference
android:defaultValue="false"
android:key="HAPTIC_FEEDBACK"
android:title="Haptic feedback"
android:summary="Enable haptic feedback (vibration) on lock." />
<CheckBoxPreference
android:defaultValue="false"
android:key="RUN_CONSTANT"
android:title="Run service when locked"
android:summary="Run service all the time, even when the screen is off, to be able to force PIN entry at any time."/>
<ListPreference
android:defaultValue="1"
android:entries="@array/array_pause_minutes"
android:entryValues="@array/array_pause_minutes_vals"
android:key="PAUSE_TIME"
android:summary="%s"
android:title="Pause time" />
</PreferenceCategory>
android:title="Pause length" />
<PreferenceCategory
android:title="Application">
<CheckBoxPreference
android:defaultValue="false"
android:key="START_ON_BOOT"
android:title="System start" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -7,7 +7,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'com.android.tools.build:gradle:3.5.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View file

@ -1 +1 @@
Initial release.
* Initial release.

View file

@ -0,0 +1,5 @@
* Animation scaling issues fixed
* Stop service correctly to fix memory leak & reduce code
* Notification priority changed to low for Nougat and lower
* Option added to run service when screen is off to be able to force PIN entry
* Gradle & library updates

View file

@ -0,0 +1,4 @@
* Fix for background service < Android 8.0/Oreo
* Add option for haptic feedback (vibration) on lock trigger
* Reworked animation logic
* Fix 'License' and 'Bug report' links on about page

View file

@ -14,4 +14,9 @@ org.gradle.jvmargs=-Xmx1536m
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
distributionSha256Sum=53b71812f18cdb2777e9f1b2a0f2038683907c90bdc406bc64d8b400e1fb2c3b

View file

@ -1,6 +1,6 @@
#Sun May 26 22:24:42 BST 2019
#Fri Sep 06 22:42:44 BST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip