/*
* MaxLock, an Xposed applock module for Android
* Copyright (C) 2014-2016 Max Rumpf alias Maxr1998
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.Maxr1998.xposed.maxlock.ui.lockscreen;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import java.util.ArrayList;
import java.util.Collections;
import de.Maxr1998.xposed.maxlock.Common;
import de.Maxr1998.xposed.maxlock.R;
public class KnockCodeHelper {
private final ArrayList<Float> knockCodeX;
private final ArrayList<Float> knockCodeY;
private final LockView mLockView;
private final FrameLayout mContainer;
private final Context mContext;
private final Paint touchColorLegacy;
private int containerX, containerY;
private Bitmap highlightLegacy;
@SuppressWarnings("deprecation")
public KnockCodeHelper(LockView lockView, FrameLayout container) {
mLockView = lockView;
mContainer = container;
mContext = mContainer.getContext();
knockCodeX = new ArrayList<>();
knockCodeY = new ArrayList<>();
if (mLockView.getPrefs().getBoolean(Common.MAKE_KC_TOUCH_VISIBLE, true)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mContainer.setForeground(mContext.obtainStyledAttributes(new int[]{R.attr.highlightDrawable}).getDrawable(0));
// Destroy others
touchColorLegacy = null;
} else {
touchColorLegacy = new Paint();
touchColorLegacy.setColor(ContextCompat.getColor(mContext, R.color.legacy_highlight_dark));
touchColorLegacy.setStrokeWidth(1);
touchColorLegacy.setStyle(Paint.Style.FILL_AND_STROKE);
}
} else {
touchColorLegacy = null;
}
mContainer.setOnTouchListener((v, e) -> {
if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
if (touchColorLegacy != null) {
float x = e.getRawX(), y = e.getRawY();
touchColorLegacy.setShader(new RadialGradient(x - containerX, y - containerY, 200,
ContextCompat.getColor(mContext, R.color.legacy_highlight_dark), Color.TRANSPARENT, Shader.TileMode.CLAMP));
Canvas c = new Canvas(highlightLegacy);
c.drawCircle(x - containerX, y - containerY, 100, touchColorLegacy);
mContainer.invalidate();
}
// Center values
int viewCenterX = containerX + mContainer.getWidth() / 2;
int viewCenterY = containerY + mContainer.getHeight() / 2;
// Track touch positions
knockCodeX.add(e.getRawX());
knockCodeY.add(e.getRawY());
if (knockCodeX.size() != knockCodeY.size()) {
throw new RuntimeException("The amount of the X and Y coordinates doesn't match!");
}
// Calculate center
float centerX;
float differenceX = Collections.max(knockCodeX) - Collections.min(knockCodeX);
if (differenceX > 50) {
centerX = Collections.min(knockCodeX) + differenceX / 2;
} else centerX = viewCenterX;
float centerY;
float differenceY = Collections.max(knockCodeY) - Collections.min(knockCodeY);
if (differenceY > 50) {
centerY = Collections.min(knockCodeY) + differenceY / 2;
} else centerY = viewCenterY;
// Calculate key
StringBuilder b = new StringBuilder(5);
for (int i = 0; i < knockCodeX.size(); i++) {
float x = knockCodeX.get(i), y = knockCodeY.get(i);
if (x < centerX && y < centerY) {
b.append('1');
} else if (x > centerX && y < centerY) {
b.append('2');
} else if (x < centerX && y > centerY) {
b.append('3');
} else if (x > centerX && y > centerY) {
b.append('4');
}
}
mLockView.setKey(b.toString(), false);
mLockView.appendToInput("\u2022");
mLockView.checkInput();
} else if (e.getActionMasked() == MotionEvent.ACTION_UP) {
if (mLockView.getPrefs().getBoolean(Common.MAKE_KC_TOUCH_VISIBLE, true) && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
highlightLegacy.eraseColor(Color.TRANSPARENT);
mContainer.invalidate();
}
}
return false;
});
if (mLockView.getPrefs().getBoolean(Common.SHOW_KC_DIVIDER, true) && !mLockView.isLandscape()) {
View divider = new View(mContext);
divider.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, Math.round(mContext.getResources().getDisplayMetrics().density)));
if (mLockView.getPrefs().getBoolean(Common.INVERT_COLOR, false)) {
divider.setBackground(mContext.getResources().getDrawable(android.R.color.black));
} else {
divider.setBackgroundColor(mContext.getResources().getColor(R.color.divider_dark));
}
mContainer.addView(divider);
}
mLockView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
@Override
public void onGlobalLayout() {
// Remove layout listener
mLockView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// Center values
int[] loc = new int[2];
mContainer.getLocationOnScreen(loc);
containerX = loc[0];
containerY = loc[1];
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
setHighlightLegacy();
}
}
});
}
public void setHighlightLegacy() {
highlightLegacy = Bitmap.createBitmap(mContainer.getWidth(), mContainer.getHeight(), Bitmap.Config.ARGB_8888);
mContainer.setBackground(new BitmapDrawable(mContainer.getResources(), highlightLegacy));
}
public void clear(boolean full) {
if (full) {
knockCodeX.clear();
knockCodeY.clear();
} else if (knockCodeX.size() > 0) {
knockCodeX.remove(knockCodeX.size() - 1);
knockCodeY.remove(knockCodeY.size() - 1);
}
}
}