mirror of
https://github.com/wesaphzt/privatelock.git
synced 2025-06-04 05:40:15 +00:00
Initial commit
This commit is contained in:
commit
fce85eb842
83 changed files with 3673 additions and 0 deletions
|
@ -0,0 +1,72 @@
|
|||
package com.wesaphzt.privatelock;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.github.paolorotolo.appintro.AppIntro;
|
||||
import com.github.paolorotolo.appintro.AppIntroFragment;
|
||||
import com.github.paolorotolo.appintro.model.SliderPage;
|
||||
|
||||
import static com.wesaphzt.privatelock.service.LockService.mInitialized;
|
||||
|
||||
public class IntroActivity extends AppIntro {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
//fullscreen
|
||||
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
//slider pages
|
||||
SliderPage sliderPageOne = new SliderPage();
|
||||
sliderPageOne.setTitle(getResources().getString(R.string.slider_page_one_title));
|
||||
sliderPageOne.setDescription(getString(R.string.slider_page_one_desc));
|
||||
sliderPageOne.setImageDrawable(R.drawable.ic_intro_lock);
|
||||
sliderPageOne.setBgColor(getResources().getColor(R.color.colorPrimary));
|
||||
addSlide(AppIntroFragment.newInstance(sliderPageOne));
|
||||
|
||||
SliderPage sliderPageTwo = new SliderPage();
|
||||
sliderPageTwo.setTitle(getResources().getString(R.string.slider_page_two_title));
|
||||
sliderPageTwo.setDescription(getResources().getString(R.string.slider_page_two_desc));
|
||||
sliderPageTwo.setImageDrawable(R.drawable.ic_intro_iris);
|
||||
sliderPageTwo.setBgColor(getResources().getColor(R.color.colorIntroGrey));
|
||||
addSlide(AppIntroFragment.newInstance(sliderPageTwo));
|
||||
|
||||
SliderPage sliderPageThree = new SliderPage();
|
||||
sliderPageThree.setTitle(getResources().getString(R.string.slider_page_three_title));
|
||||
sliderPageThree.setDescription(getResources().getString(R.string.slider_page_three_desc));
|
||||
sliderPageThree.setImageDrawable(R.drawable.ic_intro_shield);
|
||||
sliderPageThree.setBgColor(getResources().getColor(R.color.colorIntroGreen));
|
||||
addSlide(AppIntroFragment.newInstance(sliderPageThree));
|
||||
|
||||
//options
|
||||
setFadeAnimation();
|
||||
showSkipButton(false);
|
||||
setProgressButtonEnabled(true);
|
||||
|
||||
//setBarColor(getResources().getColor(R.color.colorPrimary));
|
||||
//setSeparatorColor(getResources().getColor(R.color.white));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkipPressed(Fragment currentFragment) {
|
||||
super.onSkipPressed(currentFragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDonePressed(Fragment currentFragment) {
|
||||
super.onDonePressed(currentFragment);
|
||||
mInitialized = false;
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlideChanged(@Nullable Fragment oldFragment, @Nullable Fragment newFragment) {
|
||||
super.onSlideChanged(oldFragment, newFragment);
|
||||
}
|
||||
}
|
453
app/src/main/java/com/wesaphzt/privatelock/MainActivity.java
Normal file
453
app/src/main/java/com/wesaphzt/privatelock/MainActivity.java
Normal file
|
@ -0,0 +1,453 @@
|
|||
package com.wesaphzt.privatelock;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
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.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.wesaphzt.privatelock.animation.Circle;
|
||||
import com.wesaphzt.privatelock.animation.CircleAngleAnimation;
|
||||
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 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;
|
||||
import static com.wesaphzt.privatelock.service.LockService.disabled;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private Context context;
|
||||
|
||||
private int mSensitivity;
|
||||
private float mLastX, mLastY, mLastZ;
|
||||
private boolean mInitialized;
|
||||
private static SensorManager mSensorManager;
|
||||
private Sensor mAccelerometer;
|
||||
private final float NOISE = (float) 2.0;
|
||||
|
||||
private SensorEventListener mActiveListener;
|
||||
|
||||
//DevicePolicyManager
|
||||
private DevicePolicyManager mDPM;
|
||||
private ComponentName mDeviceAdmin;
|
||||
|
||||
private static final int REQUEST_CODE_ENABLE_ADMIN = 1;
|
||||
|
||||
private TextView tvSensitivityActualValue;
|
||||
|
||||
private SharedPreferences prefs;
|
||||
public static final String PREFS_THRESHOLD = "THRESHOLD";
|
||||
|
||||
private CountDownTimer cdTimer;
|
||||
private final int cdTimerLength = 2000;
|
||||
private boolean isRunning = false;
|
||||
|
||||
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;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
context = getApplicationContext();
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
|
||||
|
||||
getFirstRun();
|
||||
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
getSupportFragmentManager().addOnBackStackChangedListener(
|
||||
new FragmentManager.OnBackStackChangedListener() {
|
||||
public void onBackStackChanged() {
|
||||
//toggle back arrow on back stack change
|
||||
if (getSupportActionBar() != null) {
|
||||
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
} else {
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
|
||||
//set title
|
||||
MainActivity.this.setTitle(R.string.app_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if(getSupportFragmentManager().getBackStackEntryCount() > 0){
|
||||
getSupportFragmentManager().popBackStack();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//https://stackoverflow.com/questions/29381474/how-to-draw-a-circle-with-animation-in-android-with-circle-size-based-on-a-value
|
||||
circle = findViewById(R.id.circle);
|
||||
circle_bg = findViewById(R.id.circle_bg);
|
||||
|
||||
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.startAnimation(animation);
|
||||
|
||||
//shared prefs
|
||||
try {
|
||||
mSensitivity = prefs.getInt(PREFS_THRESHOLD, DEFAULT_SENSITIVITY);
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(context, "Unable to retrieve threshold", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
//timer when lock hit
|
||||
cdTimer = new CountDownTimer(cdTimerLength, 1000) {
|
||||
public void onTick(long millisUntilFinished) {
|
||||
isRunning = true;
|
||||
}
|
||||
public void onFinish() {
|
||||
isRunning = false;
|
||||
circle.setColor(circleDefaultR, circleDefaultG, circleDefaultB);
|
||||
}
|
||||
};
|
||||
|
||||
//prevent lock animation artifacts
|
||||
mInitialized = false;
|
||||
|
||||
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
//sensor listener
|
||||
setSensorListener();
|
||||
mSensorManager.registerListener(mActiveListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
|
||||
//dpm
|
||||
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mDeviceAdmin = new ComponentName(this, DeviceAdminReceiver.class);
|
||||
|
||||
tvSensitivityActualValue = findViewById(R.id.tvSensitivityActualValue);
|
||||
tvSensitivityActualValue.setText(getString(R.string.sensitivity_value, Integer.toString(mSensitivity)));
|
||||
|
||||
//seek bar
|
||||
SeekBar sbSensitivity = findViewById(R.id.sbSensitivity);
|
||||
sbSensitivity.setProgress(mSensitivity);
|
||||
sbSensitivity.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
mSensitivity = progress;
|
||||
tvSensitivityActualValue.setText(getString(R.string.sensitivity_value, Integer.toString(mSensitivity)));
|
||||
|
||||
//submit to shared prefs
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putInt(PREFS_THRESHOLD, progress).apply();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) { }
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) { }
|
||||
});
|
||||
}
|
||||
|
||||
private void startLockService(Intent intent) {
|
||||
//check android api
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(intent);
|
||||
minimizeApp();
|
||||
} else {
|
||||
context.startService(intent);
|
||||
minimizeApp();
|
||||
}
|
||||
}
|
||||
|
||||
public void minimizeApp() {
|
||||
Intent startMain = new Intent(Intent.ACTION_MAIN);
|
||||
startMain.addCategory(Intent.CATEGORY_HOME);
|
||||
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(startMain);
|
||||
}
|
||||
|
||||
public void requestDeviceAdmin() {
|
||||
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
|
||||
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdmin);
|
||||
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
//launch service if permission granted
|
||||
if (requestCode == REQUEST_CODE_ENABLE_ADMIN) {
|
||||
if(resultCode == Activity.RESULT_OK) {
|
||||
startServicePrep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//determine if we are an active admin
|
||||
private boolean isActiveAdmin() {
|
||||
return mDPM.isAdminActive(mDeviceAdmin);
|
||||
}
|
||||
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mSensorManager.registerListener(mActiveListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
//recreate menu to set start/stop again
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
mSensorManager.unregisterListener(mActiveListener);
|
||||
}
|
||||
|
||||
private void setSensorListener() {
|
||||
mActiveListener = new SensorEventListener() {
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
sensorCalc(event);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
//inflate actionbar menu
|
||||
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
|
||||
Fragment fragment = null;
|
||||
|
||||
if (id == R.id.action_start) {
|
||||
if (isActiveAdmin()) {
|
||||
startServicePrep();
|
||||
} else {
|
||||
requestDeviceAdmin();
|
||||
}
|
||||
} else if (id == R.id.action_stop) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.deleteNotificationChannel(CHANNEL_ID);
|
||||
|
||||
disabled = true;
|
||||
mSensorManager.unregisterListener(activeListener);
|
||||
|
||||
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
|
||||
lockWidgetProvider.setWidgetStop(context);
|
||||
|
||||
invalidateOptionsMenu();
|
||||
} else {
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(LockService.NOTIFICATION_ID);
|
||||
|
||||
disabled = true;
|
||||
mSensorManager.unregisterListener(activeListener);
|
||||
|
||||
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
|
||||
lockWidgetProvider.setWidgetStop(context);
|
||||
}
|
||||
} else if (id == R.id.action_settings) {
|
||||
fragment = new FragmentSettings();
|
||||
} else if (id == R.id.action_donate) {
|
||||
fragment = new FragmentDonate();
|
||||
} else if (id == R.id.action_show_intro) {
|
||||
Intent myIntent = new Intent(this, IntroActivity.class);
|
||||
this.startActivity(myIntent);
|
||||
} else if (id == R.id.action_about) {
|
||||
fragment = new FragmentAbout();
|
||||
}
|
||||
|
||||
//add fragment
|
||||
if (fragment != null) {
|
||||
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
|
||||
fragmentTransaction.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left);
|
||||
fragmentTransaction.add(R.id.content_main, fragment);
|
||||
fragmentTransaction.addToBackStack(null);
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
MenuItem action_start = menu.findItem(R.id.action_start);
|
||||
MenuItem action_stop = menu.findItem(R.id.action_stop);
|
||||
|
||||
setMenuStatus(action_start, action_stop);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setMenuStatus(MenuItem action_start, MenuItem action_stop) {
|
||||
if (disabled) {
|
||||
action_start.setEnabled(true);
|
||||
action_stop.setEnabled(false);
|
||||
} else {
|
||||
//enabled
|
||||
action_start.setEnabled(false);
|
||||
action_stop.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void getFirstRun() {
|
||||
//get current version code
|
||||
int currentVersionCode = BuildConfig.VERSION_CODE;
|
||||
//get saved version code
|
||||
int savedVersionCode = DOESNT_EXIST;
|
||||
try {
|
||||
savedVersionCode = this.prefs.getInt(PREF_VERSION_CODE_KEY, DOESNT_EXIST);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//check first run
|
||||
//noinspection StatementWithEmptyBody
|
||||
if (currentVersionCode == savedVersionCode) {
|
||||
//normal run
|
||||
} else if (savedVersionCode == DOESNT_EXIST) {
|
||||
//first run
|
||||
Intent myIntent = new Intent(this, IntroActivity.class);
|
||||
this.startActivity(myIntent);
|
||||
}
|
||||
//update shared prefs with current version code
|
||||
this.prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply();
|
||||
}
|
||||
|
||||
private void sensorCalc(SensorEvent event) {
|
||||
float x = event.values[0];
|
||||
float y = event.values[1];
|
||||
float z = event.values[2];
|
||||
|
||||
if (!mInitialized) {
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
mLastZ = z;
|
||||
|
||||
mInitialized = true;
|
||||
} else {
|
||||
float deltaX = Math.abs(mLastX - x);
|
||||
float deltaY = Math.abs(mLastY - y);
|
||||
float deltaZ = Math.abs(mLastZ - z);
|
||||
|
||||
if (deltaX < NOISE) deltaX = (float) 0.0;
|
||||
if (deltaY < NOISE) deltaY = (float) 0.0;
|
||||
if (deltaZ < NOISE) deltaZ = (float) 0.0;
|
||||
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
mLastZ = z;
|
||||
|
||||
float total = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
|
||||
|
||||
int calculatedAngleInt;
|
||||
|
||||
if (total <= mSensitivity) {
|
||||
//do nothing if timer currently running
|
||||
if(isRunning)
|
||||
return;
|
||||
|
||||
calculatedAngleInt = Math.round((total / mSensitivity) * 360);
|
||||
|
||||
CircleAngleAnimation 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.wesaphzt.privatelock.animation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
public class Circle extends View {
|
||||
|
||||
private static final int START_ANGLE_POINT = 90;
|
||||
|
||||
private final Paint paint;
|
||||
private final RectF rect;
|
||||
|
||||
private float angle;
|
||||
|
||||
public Circle(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
final int strokeWidth = 10;
|
||||
|
||||
paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
//circle color (currently set upon instance)
|
||||
//paint.setColor(Color.BLUE);
|
||||
|
||||
//size
|
||||
rect = new RectF(strokeWidth, strokeWidth, 600 + strokeWidth, 600 + strokeWidth);
|
||||
|
||||
//initial angle (optional)
|
||||
angle = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawArc(rect, START_ANGLE_POINT, angle, true, paint);
|
||||
}
|
||||
|
||||
public float getAngle() {
|
||||
return angle;
|
||||
}
|
||||
|
||||
public void setColor(int r, int g, int b) {
|
||||
paint.setColor(Color.rgb(r, g, b));
|
||||
}
|
||||
|
||||
public void setAngle(float angle) {
|
||||
this.angle = angle;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.wesaphzt.privatelock.animation;
|
||||
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
public class CircleAngleAnimation extends Animation {
|
||||
|
||||
private Circle circle;
|
||||
|
||||
private float oldAngle;
|
||||
private float newAngle;
|
||||
|
||||
public CircleAngleAnimation(Circle circle, int newAngle) {
|
||||
this.oldAngle = circle.getAngle();
|
||||
this.newAngle = newAngle;
|
||||
this.circle = circle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
|
||||
float angle = oldAngle + ((newAngle - oldAngle) * interpolatedTime);
|
||||
|
||||
circle.setAngle(angle);
|
||||
circle.requestLayout();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
package com.wesaphzt.privatelock.fragments;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
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 AUTHOR_GITHUB;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_about, container, false);
|
||||
|
||||
GITHUB_URI = getString(R.string.app_github);
|
||||
AUTHOR_GITHUB = getString(R.string.app_github_dev);
|
||||
|
||||
String versionName = "";
|
||||
try {
|
||||
PackageInfo packageInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0);
|
||||
versionName = packageInfo.versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
TextView version = v.findViewById(R.id.about_text_version);
|
||||
version.setText(versionName);
|
||||
|
||||
LinearLayout license = v.findViewById(R.id.about_layout_license);
|
||||
LinearLayout source = v.findViewById(R.id.about_layout_source);
|
||||
|
||||
license.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
openURI(LICENSE_URI);
|
||||
}
|
||||
});
|
||||
source.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
openURI(GITHUB_URI);
|
||||
}
|
||||
});
|
||||
|
||||
LinearLayout authorLayout = v.findViewById(R.id.aboutLayoutAuthor);
|
||||
authorLayout.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
openURI(AUTHOR_GITHUB);
|
||||
}
|
||||
});
|
||||
|
||||
LinearLayout bugReport = v.findViewById(R.id.about_layout_bugs);
|
||||
bugReport.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
openURI(BUG_REPORT_URI);
|
||||
}
|
||||
});
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
private void openURI(String uri) {
|
||||
try {
|
||||
Intent openURI = new Intent(Intent.ACTION_VIEW);
|
||||
openURI.setData(Uri.parse(uri));
|
||||
startActivity(openURI);
|
||||
} catch (Exception e) {
|
||||
Log.d("app-error", "error opening uri");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//hide action bar menu
|
||||
menu.setGroupVisible(R.id.menu_main, false);
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
//set title
|
||||
getActivity().setTitle(getString(R.string.fragment_about_title));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
package com.wesaphzt.privatelock.fragments;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.wesaphzt.privatelock.R;
|
||||
|
||||
public class FragmentDonate extends Fragment {
|
||||
|
||||
private Context context;
|
||||
|
||||
private static final String BITCOIN_PREFIX = "bitcoin:";
|
||||
private static final String LITECOIN_PREFIX = "litecoin:";
|
||||
private static final String ETHEREUM_PREFIX = "ethereum:";
|
||||
private static final String MONERO_PREFIX = "monero:";
|
||||
|
||||
private static String BITCOIN_ADDRESS;
|
||||
private static String BITCOIN_FULL;
|
||||
|
||||
private static String LITECOIN_ADDRESS;
|
||||
private static String LITECOIN_FULL;
|
||||
|
||||
private static String ETHEREUM_ADDRESS;
|
||||
private static String ETHEREUM_FULL;
|
||||
|
||||
private static String MONERO_ADDRESS;
|
||||
private static String MONERO_FULL;
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_donate, container, false);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
context = getContext();
|
||||
|
||||
final TextView tvAddressBtc = view.findViewById(R.id.donate_bitcoin_address);
|
||||
final TextView tvAddressLtc = view.findViewById(R.id.donate_litecoin_address);
|
||||
final TextView tvAddressEth = view.findViewById(R.id.donate_ethereum_address);
|
||||
final TextView tvAddressXmr = view.findViewById(R.id.donate_monero_address);
|
||||
|
||||
BITCOIN_ADDRESS = getString(R.string.donate_bitcoin_address);
|
||||
BITCOIN_FULL = BITCOIN_PREFIX + BITCOIN_ADDRESS;
|
||||
tvAddressBtc.setText(BITCOIN_ADDRESS);
|
||||
|
||||
LITECOIN_ADDRESS = getString(R.string.donate_litecoin_address);
|
||||
LITECOIN_FULL = LITECOIN_PREFIX + LITECOIN_ADDRESS;
|
||||
tvAddressLtc.setText(LITECOIN_ADDRESS);
|
||||
|
||||
ETHEREUM_ADDRESS = getString(R.string.donate_ethereum_address);
|
||||
ETHEREUM_FULL = ETHEREUM_PREFIX + ETHEREUM_ADDRESS;
|
||||
tvAddressEth.setText(ETHEREUM_ADDRESS);
|
||||
|
||||
MONERO_ADDRESS = getString(R.string.donate_monero_address);
|
||||
MONERO_FULL = MONERO_PREFIX + MONERO_ADDRESS;
|
||||
tvAddressXmr.setText(MONERO_ADDRESS);
|
||||
|
||||
tvAddressBtc.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
//attempt to open bitcoin app, else copy to clipboard
|
||||
try {
|
||||
openURI(BITCOIN_FULL);
|
||||
} catch(Exception ignored) {
|
||||
copyToClipboard(BITCOIN_ADDRESS);
|
||||
}
|
||||
}
|
||||
});
|
||||
tvAddressBtc.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
copyToClipboard(BITCOIN_ADDRESS);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//litecoin
|
||||
tvAddressLtc.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
//attempt to open litecoin app, else copy to clipboard
|
||||
try {
|
||||
openURI(LITECOIN_FULL);
|
||||
} catch(Exception ignored) {
|
||||
copyToClipboard(LITECOIN_ADDRESS);
|
||||
}
|
||||
}
|
||||
});
|
||||
tvAddressLtc.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
copyToClipboard(LITECOIN_ADDRESS);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//ethereum
|
||||
tvAddressEth.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
//attempt to open ethereum app, else copy to clipboard
|
||||
try {
|
||||
openURI(ETHEREUM_FULL);
|
||||
} catch(Exception ignored) {
|
||||
copyToClipboard(ETHEREUM_ADDRESS);
|
||||
}
|
||||
}
|
||||
});
|
||||
tvAddressEth.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
copyToClipboard(ETHEREUM_ADDRESS);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//monero
|
||||
tvAddressXmr.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
//attempt to open ethereum app, else copy to clipboard
|
||||
try {
|
||||
openURI(MONERO_FULL);
|
||||
} catch(Exception ignored) {
|
||||
copyToClipboard(MONERO_ADDRESS);
|
||||
}
|
||||
}
|
||||
});
|
||||
tvAddressXmr.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
copyToClipboard(MONERO_ADDRESS);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void copyToClipboard(String AUTHOR_EXTRA) {
|
||||
ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(getString(R.string.fragment_donate_clipboard_label), AUTHOR_EXTRA);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
|
||||
Toast.makeText(context, R.string.fragment_donate_clipboard_message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void openURI(String uri) {
|
||||
Intent openURI = new Intent(Intent.ACTION_VIEW);
|
||||
openURI.setData(Uri.parse(uri));
|
||||
startActivity(openURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//hide action bar menu
|
||||
menu.setGroupVisible(R.id.menu_main, false);
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
//set title
|
||||
getActivity().setTitle(getString(R.string.fragment_donate_title));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.wesaphzt.privatelock.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import com.wesaphzt.privatelock.R;
|
||||
|
||||
public class FragmentSettings extends PreferenceFragmentCompat {
|
||||
|
||||
private SharedPreferences prefs;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
Context context = getContext();
|
||||
|
||||
//this static call will reset default values only on the first read
|
||||
PreferenceManager.setDefaultValues(context, R.xml.preferences, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
//set title
|
||||
getActivity().setTitle("Settings");
|
||||
|
||||
//bg color
|
||||
view.setBackgroundColor(getResources().getColor(R.color.white));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//hide action bar menu
|
||||
menu.setGroupVisible(R.id.menu_main, false);
|
||||
|
||||
super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.wesaphzt.privatelock.receivers;
|
||||
|
||||
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;
|
||||
|
||||
public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);;
|
||||
if(prefs.getBoolean("START_ON_BOOT", false)) {
|
||||
Intent i = new Intent(context, LockService.class);
|
||||
|
||||
//check android api
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(i);
|
||||
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
|
||||
lockWidgetProvider.setWidgetStart(context);
|
||||
} else {
|
||||
context.startService(i);
|
||||
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
|
||||
lockWidgetProvider.setWidgetStart(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.wesaphzt.privatelock.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class DeviceAdminReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
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 {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
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();
|
||||
|
||||
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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.wesaphzt.privatelock.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.CountDownTimer;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.wesaphzt.privatelock.widget.LockWidgetProvider;
|
||||
|
||||
import static com.wesaphzt.privatelock.service.LockService.disabled;
|
||||
import static com.wesaphzt.privatelock.service.LockService.mInitialized;
|
||||
|
||||
public class PauseReceiver extends BroadcastReceiver {
|
||||
|
||||
public static CountDownTimer mCountdown;
|
||||
public static boolean isRunning = false;
|
||||
|
||||
@Override
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
String action = intent.getStringExtra("pause_service");
|
||||
|
||||
if (action.equals("pause_service_time")) {
|
||||
//close notification tray
|
||||
Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
context.sendBroadcast(i);
|
||||
|
||||
if(disabled) {
|
||||
Toast.makeText(context, "Service is already paused", Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
} else {
|
||||
disabled = true;
|
||||
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
|
||||
lockWidgetProvider.setWidgetPause(context);
|
||||
}
|
||||
|
||||
//shared prefs
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
int pauseMinuteTime = Integer.parseInt(prefs.getString("PAUSE_TIME", String.valueOf(1)));
|
||||
int milliPauseTime = pauseMinuteTime * 60 * 1000;
|
||||
|
||||
String plural;
|
||||
if(pauseMinuteTime == 1) { plural = "minute"; } else { plural = "minutes"; }
|
||||
|
||||
Toast.makeText(context, "Service paused for " + pauseMinuteTime + " " + plural, Toast.LENGTH_LONG).show();
|
||||
|
||||
mCountdown = new CountDownTimer(milliPauseTime, 1000) {
|
||||
public void onTick(long millisUntilFinished) {
|
||||
isRunning = true;
|
||||
}
|
||||
public void onFinish() {
|
||||
//prevent lock animation artifacts
|
||||
mInitialized = false;
|
||||
//init
|
||||
disabled = false;
|
||||
isRunning = false;
|
||||
LockWidgetProvider lockWidgetProvider = new LockWidgetProvider();
|
||||
lockWidgetProvider.setWidgetStart(context);
|
||||
|
||||
Toast.makeText(context, "Service resumed", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.wesaphzt.privatelock.receivers;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import static com.wesaphzt.privatelock.service.LockService.disabled;
|
||||
import static com.wesaphzt.privatelock.service.LockService.mInitialized;
|
||||
|
||||
public class PresenceReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
|
||||
//prevent lock animation artifacts
|
||||
mInitialized = false;
|
||||
|
||||
disabled = false;
|
||||
|
||||
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
package com.wesaphzt.privatelock.service;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.JobIntentService;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.wesaphzt.privatelock.MainActivity;
|
||||
import com.wesaphzt.privatelock.R;
|
||||
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 static androidx.core.app.NotificationCompat.PRIORITY_MIN;
|
||||
|
||||
public class LockService extends JobIntentService {
|
||||
|
||||
private Context context;
|
||||
|
||||
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;
|
||||
public static boolean disabled = true;
|
||||
|
||||
//DevicePolicyManager
|
||||
DevicePolicyManager mDPM;
|
||||
ComponentName mDeviceAdmin;
|
||||
|
||||
//notifications
|
||||
Notification notification;
|
||||
NotificationManager notificationManager;
|
||||
//ids
|
||||
public static String CHANNEL_ID;
|
||||
public static String CHANNEL_NAME;
|
||||
public static final int NOTIFICATION_ID = 1000;
|
||||
//intents
|
||||
public static PendingIntent pendingIntent;
|
||||
public static PendingIntent pendingCloseIntent;
|
||||
public static PendingIntent pendingPauseIntent;
|
||||
|
||||
//sensitivity
|
||||
public static final int DEFAULT_SENSITIVITY = 10;
|
||||
public static int SENSITIVITY;
|
||||
|
||||
@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();
|
||||
|
||||
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);
|
||||
|
||||
//dpm
|
||||
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
|
||||
mDeviceAdmin = new ComponentName(this, DeviceAdminReceiver.class);
|
||||
|
||||
//prevent lock animation artifacts
|
||||
mInitialized = false;
|
||||
|
||||
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
||||
setSensorListener();
|
||||
mSensorManager.registerListener(activeListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
|
||||
|
||||
setNotification();
|
||||
//------------------------------------------------------------------------------------------
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
//create foreground service
|
||||
startForeground(NOTIFICATION_ID, notification);
|
||||
disabled = false;
|
||||
|
||||
} else {
|
||||
notificationManager.notify(NOTIFICATION_ID, notification);
|
||||
disabled = false;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------
|
||||
|
||||
return LockService.START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleWork(@NonNull Intent intent) { }
|
||||
|
||||
private void setSensorListener() {
|
||||
activeListener = new SensorEventListener() {
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if(LockService.disabled)
|
||||
return;
|
||||
|
||||
sensorCalc(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) { }
|
||||
};
|
||||
}
|
||||
|
||||
private void sensorCalc(SensorEvent event) {
|
||||
float x = event.values[0];
|
||||
float y = event.values[1];
|
||||
float z = event.values[2];
|
||||
|
||||
if (!mInitialized) {
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
mLastZ = z;
|
||||
|
||||
mInitialized = true;
|
||||
} else {
|
||||
float deltaX = Math.abs(mLastX - x);
|
||||
float deltaY = Math.abs(mLastY - y);
|
||||
float deltaZ = Math.abs(mLastZ - z);
|
||||
|
||||
if (deltaX < NOISE) deltaX = (float) 0.0;
|
||||
if (deltaY < NOISE) deltaY = (float) 0.0;
|
||||
if (deltaZ < NOISE) deltaZ = (float) 0.0;
|
||||
|
||||
mLastX = x;
|
||||
mLastY = y;
|
||||
mLastZ = z;
|
||||
|
||||
float total = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
|
||||
|
||||
if (total > SENSITIVITY) {
|
||||
try {
|
||||
mDPM.lockNow();
|
||||
} catch (Exception e) {
|
||||
Toast.makeText(context, "Error locking, does app have device admin permissions?", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotification() {
|
||||
//notification
|
||||
pendingIntent = PendingIntent.getActivity(context, 0,
|
||||
new Intent(context, MainActivity.class)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP),
|
||||
0);
|
||||
|
||||
//notification stop button
|
||||
Intent intentStopAction = new Intent(context, NotificationReceiver.class);
|
||||
intentStopAction.putExtra("lock_service","lock_service_notification");
|
||||
pendingCloseIntent = PendingIntent.getBroadcast(context,0, intentStopAction, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
//notification pause button
|
||||
Intent intentPauseAction = new Intent(context, PauseReceiver.class);
|
||||
intentPauseAction.putExtra("pause_service","pause_service_time");
|
||||
pendingPauseIntent = PendingIntent.getBroadcast(context,0, intentPauseAction, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
NotificationCompat.Builder notificationBuilder;
|
||||
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
notificationBuilder = new NotificationCompat.Builder(this);
|
||||
notification = notificationBuilder
|
||||
.setSmallIcon(R.drawable.ic_lock_white_24dp)
|
||||
.setContentTitle(getString(R.string.app_name) + " is running")
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.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)
|
||||
.setOngoing(true)
|
||||
.build();
|
||||
|
||||
} else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N| Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
|
||||
notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
|
||||
notification = notificationBuilder
|
||||
.setSmallIcon(R.drawable.ic_lock_white_24dp)
|
||||
.setContentTitle(getString(R.string.app_name) + " is running")
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setColor(getColor(R.color.colorPrimary))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.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)
|
||||
.setOngoing(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
|
||||
channel.setImportance(NotificationManager.IMPORTANCE_LOW);
|
||||
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
|
||||
notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
|
||||
notification = notificationBuilder
|
||||
.setSmallIcon(R.drawable.ic_lock_white_24dp)
|
||||
.setContentTitle(getString(R.string.app_name) + " is running")
|
||||
.setPriority(PRIORITY_MIN)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_SECRET)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setColor(getColor(R.color.colorPrimary))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.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)
|
||||
.setOngoing(true)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package com.wesaphzt.privatelock.widget;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
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 {
|
||||
|
||||
private static final String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
|
||||
public boolean SERVICE_STATUS;
|
||||
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
|
||||
int[] appWidgetIds) {
|
||||
|
||||
for (int appWidgetId : appWidgetIds) {
|
||||
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
|
||||
R.layout.app_widget);
|
||||
|
||||
//default status
|
||||
remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_start_text));
|
||||
|
||||
Intent intent = new Intent(context, LockWidgetProvider.class);
|
||||
intent.setAction(ACTION_WIDGET_RECEIVER);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
|
||||
0, intent, 0);
|
||||
|
||||
remoteViews.setOnClickPendingIntent(R.id.llWidget, pendingIntent);
|
||||
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
boolean value = prefs.getBoolean(context.getString(R.string.widget_prefs_service_id), false);
|
||||
|
||||
if (value) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(ACTION_WIDGET_RECEIVER)) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
boolean value = prefs.getBoolean(context.getString(R.string.widget_prefs_service_id), false);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
SERVICE_STATUS = value;
|
||||
|
||||
//if service is running
|
||||
if (SERVICE_STATUS) {
|
||||
editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
|
||||
editor.apply();
|
||||
|
||||
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_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);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
//if service is not running
|
||||
} else {
|
||||
editor.putBoolean(context.getString(R.string.widget_prefs_service_id), true);
|
||||
editor.commit();
|
||||
|
||||
Intent i = new Intent(context, LockService.class);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
disabled = false;
|
||||
context.startForegroundService(i);
|
||||
setWidgetStart(context);
|
||||
} else {
|
||||
disabled = false;
|
||||
context.startService(i);
|
||||
setWidgetStart(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(Context context, int[] appWidgetIds) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
boolean value = prefs.getBoolean(context.getString(R.string.widget_prefs_service_id), false);
|
||||
|
||||
if (value) {
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putBoolean(context.getString(R.string.widget_prefs_service_id), false);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
super.onDeleted(context, appWidgetIds);
|
||||
}
|
||||
|
||||
//update widget methods
|
||||
public void setWidgetStart(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
prefs.edit().putBoolean(context.getString(R.string.widget_prefs_service_id), true).apply();
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
ComponentName thisWidget = new ComponentName(context, LockWidgetProvider.class);
|
||||
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.app_widget);
|
||||
|
||||
remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_stop_text));
|
||||
remoteViews.setImageViewResource(R.id.ivWidgetLock, R.drawable.ic_lock_closed_outline_white_24dp);
|
||||
remoteViews.setInt(R.id.llWidget, "setBackgroundResource", R.color.colorWidgetStart);
|
||||
|
||||
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
|
||||
}
|
||||
|
||||
public void setWidgetStop(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
prefs.edit().putBoolean(context.getString(R.string.widget_prefs_service_id), false).apply();
|
||||
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
ComponentName thisWidget = new ComponentName(context, LockWidgetProvider.class);
|
||||
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.app_widget);
|
||||
|
||||
remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_start_text));
|
||||
remoteViews.setImageViewResource(R.id.ivWidgetLock, R.drawable.ic_lock_open_outline_white_24dp);
|
||||
remoteViews.setInt(R.id.llWidget, "setBackgroundResource", R.color.colorWidgetStop);
|
||||
|
||||
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
|
||||
}
|
||||
|
||||
public void setWidgetPause(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(context);
|
||||
prefs.edit().putBoolean(context.getString(R.string.widget_prefs_service_id), true).apply();
|
||||
|
||||
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
ComponentName thisWidget = new ComponentName(context, LockWidgetProvider.class);
|
||||
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.app_widget);
|
||||
|
||||
remoteViews.setTextViewText(R.id.tvWidgetToggle, context.getResources().getString(R.string.widget_stop_text));
|
||||
remoteViews.setImageViewResource(R.id.ivWidgetLock, R.drawable.ic_lock_open_outline_white_24dp);
|
||||
remoteViews.setInt(R.id.llWidget, "setBackgroundResource", R.color.colorWidgetPause);
|
||||
|
||||
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue