├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── encodings.xml
├── gradle.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app-release.apk
├── app-release_htc.apk
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── ColorPickerPreference
│ │ ├── .gitignore
│ │ ├── build.gradle
│ │ ├── proguard-rules.pro
│ │ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── net
│ │ │ └── margaritov
│ │ │ └── colorpickerpreference
│ │ │ └── ApplicationTest.java
│ │ └── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ └── net
│ │ │ └── margaritov
│ │ │ └── preference
│ │ │ └── colorpicker
│ │ │ ├── AlphaPatternDrawable.java
│ │ │ ├── ColorPickerDialog.java
│ │ │ ├── ColorPickerPanelView.java
│ │ │ ├── ColorPickerPreference.java
│ │ │ └── ColorPickerView.java
│ │ └── res
│ │ ├── layout-land
│ │ └── dialog_color_picker.xml
│ │ ├── layout
│ │ └── dialog_color_picker.xml
│ │ └── values
│ │ └── strings.xml
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── xposed_init
│ ├── java
│ └── me
│ │ └── rijul
│ │ └── knockcode
│ │ ├── AboutActivity.java
│ │ ├── AppearAnimationCreator.java
│ │ ├── AppearAnimationUtils.java
│ │ ├── CustomShortcutActivity.java
│ │ ├── DisappearAnimationUtils.java
│ │ ├── DotsView.java
│ │ ├── Grid.java
│ │ ├── KeyguardKnockView.java
│ │ ├── KillReceiver.java
│ │ ├── LockButtonView.java
│ │ ├── MainActivity.java
│ │ ├── SecurePreferences.java
│ │ ├── SeekBarPreference.java
│ │ ├── SettingsActivity.java
│ │ ├── SettingsHelper.java
│ │ ├── ShortcutPickHelper.java
│ │ ├── Utils.java
│ │ └── XposedMod.java
│ └── res
│ ├── layout
│ ├── activity_settings.xml
│ ├── custom_shortcut_row.xml
│ ├── dialog_checkbox.xml
│ ├── fragment_list.xml
│ ├── fragment_main.xml
│ ├── grid_number_picker.xml
│ ├── main.xml
│ └── slider_preference.xml
│ ├── menu
│ ├── menu_custom_shortcuts.xml
│ └── menu_settings.xml
│ ├── mipmap-hdpi
│ └── ic_launcher.png
│ ├── mipmap-mdpi
│ └── ic_launcher.png
│ ├── mipmap-xhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxhdpi
│ └── ic_launcher.png
│ ├── mipmap-xxxhdpi
│ └── ic_launcher.png
│ ├── values-id
│ └── strings.xml
│ ├── values-pl
│ └── strings.xml
│ ├── values-pt-rBR
│ └── strings.xml
│ ├── values-ru
│ └── strings.xml
│ ├── values
│ ├── arrays.xml
│ ├── colors.xml
│ ├── dimen.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ ├── about.xml
│ └── settings.xml
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenShots
├── changeCode.jpg
├── customShortcutSelector.jpg
├── customShortcuts.jpg
├── gridSizeSelector.jpg
├── lockScreen.jpg
└── someSettings.jpg
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | /app/src/main/java/me/rijul/knockcode/CustomLogger.java
10 | crowdin.yaml
11 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Knock Code with Custom Shortcuts
2 | 
3 |
4 | This Xposed module enables LG's Knock Code for Lollipop and Marshmallow devices . The unlock method is highly customizable, from changing colours to visibility, error messages, background, etc. You can even hide the emergency button.
5 |
6 | What's more, you can use codes to directly open specific shortcuts from the lockscreen, for example use 11212 to unlock, 221 to open WhatsApp, 1122 for email, etc. These shortcuts don't have to be just apps, they can be anything on your device, like Direct Dial, open a specific Contact, etc.
7 |
8 | The module is pretty self explanatory, and will prompt you to set a pattern on the lock screen, because that is what it replaces. Other than that, there are no specific instructions to use it. Should the module or Xposed be disabled for any reason, your phone will still remain secure with that pattern.
9 |
10 | Compatibility :
11 | I personally test on CM13, and I will support CM12.0, CM12.1, AOSP 5.x and 6.0.x and derivatives. HTC support is limited unless I find a tester. Support for other OEM ROMs is absent beyond basic working functionality.
12 |
13 | The only caveats are because of the way Xposed works.
14 | + Your code(s) will be visible to any one or any app on your device. No root required. The codes are stored encrypted, but anybody determined to get them will be able to, provided they can lay hands on your device. One way to avoid this is to disable USB debugging to prevent chances of a local exploit.
15 | + You need root to restart the keyguard after changing the full screen option. It is not mandatory, you could manually reboot if you require. All other changes will be reflected automatically, but not this one.
16 |
17 | Screenshots:
18 | ------
19 | 
20 | 
21 | 
22 | [More Screenshots](https://github.com/Rijul-Ahuja/Xposed-Knock-Code/blob/master/screenShots/)
23 |
24 | Links:
25 | ------
26 | + [XDA Forum](http://forum.xda-developers.com/xposed/modules/lp-knock-code-screen-t3272679)
27 | + [Xposed Repo](http://repo.xposed.info/module/me.rijul.knockcode)
28 |
29 | Thanks to:
30 | ------
31 | + [ColorPickerPreference](https://github.com/attenzione/android-ColorPickerPreference)
32 | + [Temasek's ShortcutPickHelper](https://github.com/temasek/android_packages_apps_Settings/blob/cm-13.0/src/com/android/settings/cyanogenmod/ShortcutPickHelper.java)
33 | + [Tyaginator@XDA for the custom shortcuts idea](http://forum.xda-developers.com/member.php?u=5327227)
34 | + [PIN/Pattern Shortcuts](http://repo.xposed.info/module/com.hamzah.pinshortcuts)
35 | + [MaxLock's Module Active Prompt](https://github.com/Maxr1998/MaxLock/blob/master/app/src/main/java/de/Maxr1998/xposed/maxlock/ui/SettingsActivity.java#L75)
36 | + [MaxLock's Launcher Icon Hider](https://github.com/Maxr1998/MaxLock/blob/master/app/src/main/java/de/Maxr1998/xposed/maxlock/ui/settings/MaxLockPreferenceFragment.java#L310)
37 | + [MohammadAG's KnockCode for the inspiration](http://repo.xposed.info/module/com.mohammadag.knockcode)
38 |
--------------------------------------------------------------------------------
/app-release.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rijul-A/Xposed-Knock-Code/82cb70d6b501d2229cc0d792166c5930f4cef9e7/app-release.apk
--------------------------------------------------------------------------------
/app-release_htc.apk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rijul-A/Xposed-Knock-Code/82cb70d6b501d2229cc0d792166c5930f4cef9e7/app-release_htc.apk
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | signingConfigs {
5 | config {
6 | keyAlias 'MyKeyStore'
7 | keyPassword 'YmdvL9d8T$M!Y2'
8 | storeFile file('/home/rijul/Android/keyStore.jks')
9 | storePassword 'YmdvL9d8T$M!Y2'
10 | }
11 | }
12 | compileSdkVersion 23
13 | buildToolsVersion "23.0.2"
14 |
15 | defaultConfig {
16 | applicationId "me.rijul.knockcode"
17 | minSdkVersion 21
18 | targetSdkVersion 22
19 | versionCode 49
20 | versionName "1.4.9 test-fix-htc"
21 | }
22 | buildTypes {
23 | release {
24 | minifyEnabled false
25 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
26 | signingConfig signingConfigs.config
27 | }
28 | }
29 | }
30 |
31 | dependencies {
32 | compile fileTree(dir: 'libs', include: ['*.jar'])
33 | provided 'de.robv.android.xposed:api:82'
34 | compile project(':ColorPickerPreference')
35 | compile 'com.google.android.gms:play-services-analytics:8.4.0'
36 | testCompile 'junit:junit:4.12'
37 | }
38 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.2"
6 |
7 | defaultConfig {
8 | minSdkVersion 7
9 | targetSdkVersion 21
10 | versionCode 1
11 | versionName "1.0"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile fileTree(dir: 'libs', include: ['*.jar'])
23 | }
24 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -optimizationpasses 5
2 | -dontusemixedcaseclassnames
3 | -dontskipnonpubliclibraryclasses
4 | -dontpreverify
5 | -verbose
6 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
7 |
8 | -keep public class * extends android.app.Activity
9 | -keep public class * extends android.app.Application
10 | -keep public class * extends android.app.Service
11 | -keep public class * extends android.content.BroadcastReceiver
12 | -keep public class * extends android.content.ContentProvider
13 | -keep public class com.android.vending.licensing.ILicensingService
14 |
15 | -keepclasseswithmembernames class * {
16 | native ;
17 | }
18 |
19 | -keepclasseswithmembernames class * {
20 | public (android.content.Context, android.util.AttributeSet);
21 | }
22 |
23 | -keepclasseswithmembernames class * {
24 | public (android.content.Context, android.util.AttributeSet, int);
25 | }
26 |
27 | -keepclassmembers enum * {
28 | public static **[] values();
29 | public static ** valueOf(java.lang.String);
30 | }
31 |
32 | -keep class * implements android.os.Parcelable {
33 | public static final android.os.Parcelable$Creator *;
34 | }
35 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/androidTest/java/net/margaritov/colorpickerpreference/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package net.margaritov.colorpickerpreference;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/AlphaPatternDrawable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.graphics.Bitmap;
20 | import android.graphics.Bitmap.Config;
21 | import android.graphics.Canvas;
22 | import android.graphics.ColorFilter;
23 | import android.graphics.Paint;
24 | import android.graphics.Rect;
25 | import android.graphics.drawable.Drawable;
26 |
27 | /**
28 | * This drawable that draws a simple white and gray chessboard pattern.
29 | * It's pattern you will often see as a background behind a
30 | * partly transparent image in many applications.
31 | *
32 | * @author Daniel Nilsson
33 | */
34 | public class AlphaPatternDrawable extends Drawable {
35 |
36 | private int mRectangleSize = 10;
37 |
38 | private Paint mPaint = new Paint();
39 | private Paint mPaintWhite = new Paint();
40 | private Paint mPaintGray = new Paint();
41 |
42 | private int numRectanglesHorizontal;
43 | private int numRectanglesVertical;
44 |
45 | /**
46 | * Bitmap in which the pattern will be cahched.
47 | */
48 | private Bitmap mBitmap;
49 |
50 | public AlphaPatternDrawable(int rectangleSize) {
51 | mRectangleSize = rectangleSize;
52 | mPaintWhite.setColor(0xffffffff);
53 | mPaintGray.setColor(0xffcbcbcb);
54 | }
55 |
56 | @Override
57 | public void draw(Canvas canvas) {
58 | canvas.drawBitmap(mBitmap, null, getBounds(), mPaint);
59 | }
60 |
61 | @Override
62 | public int getOpacity() {
63 | return 0;
64 | }
65 |
66 | @Override
67 | public void setAlpha(int alpha) {
68 | throw new UnsupportedOperationException("Alpha is not supported by this drawwable.");
69 | }
70 |
71 | @Override
72 | public void setColorFilter(ColorFilter cf) {
73 | throw new UnsupportedOperationException("ColorFilter is not supported by this drawwable.");
74 | }
75 |
76 | @Override
77 | protected void onBoundsChange(Rect bounds) {
78 | super.onBoundsChange(bounds);
79 |
80 | int height = bounds.height();
81 | int width = bounds.width();
82 |
83 | numRectanglesHorizontal = (int) Math.ceil((width / mRectangleSize));
84 | numRectanglesVertical = (int) Math.ceil(height / mRectangleSize);
85 |
86 | generatePatternBitmap();
87 |
88 | }
89 |
90 | /**
91 | * This will generate a bitmap with the pattern
92 | * as big as the rectangle we were allow to draw on.
93 | * We do this to chache the bitmap so we don't need to
94 | * recreate it each time draw() is called since it
95 | * takes a few milliseconds.
96 | */
97 | private void generatePatternBitmap() {
98 |
99 | if (getBounds().width() <= 0 || getBounds().height() <= 0) {
100 | return;
101 | }
102 |
103 | mBitmap = Bitmap.createBitmap(getBounds().width(), getBounds().height(), Config.ARGB_8888);
104 | Canvas canvas = new Canvas(mBitmap);
105 |
106 | Rect r = new Rect();
107 | boolean verticalStartWhite = true;
108 | for (int i = 0; i <= numRectanglesVertical; i++) {
109 |
110 | boolean isWhite = verticalStartWhite;
111 | for (int j = 0; j <= numRectanglesHorizontal; j++) {
112 |
113 | r.top = i * mRectangleSize;
114 | r.left = j * mRectangleSize;
115 | r.bottom = r.top + mRectangleSize;
116 | r.right = r.left + mRectangleSize;
117 |
118 | canvas.drawRect(r, isWhite ? mPaintWhite : mPaintGray);
119 |
120 | isWhite = !isWhite;
121 | }
122 |
123 | verticalStartWhite = !verticalStartWhite;
124 |
125 | }
126 |
127 | }
128 |
129 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.app.Dialog;
20 | import android.content.Context;
21 | import android.content.res.ColorStateList;
22 | import android.graphics.Color;
23 | import android.graphics.PixelFormat;
24 | import android.os.Bundle;
25 | import android.text.InputFilter;
26 | import android.text.InputType;
27 | import android.view.KeyEvent;
28 | import android.view.LayoutInflater;
29 | import android.view.View;
30 | import android.view.ViewTreeObserver;
31 | import android.view.inputmethod.EditorInfo;
32 | import android.view.inputmethod.InputMethodManager;
33 | import android.widget.EditText;
34 | import android.widget.LinearLayout;
35 | import android.widget.TextView;
36 |
37 | import java.util.Locale;
38 |
39 | public class ColorPickerDialog
40 | extends
41 | Dialog
42 | implements
43 | ColorPickerView.OnColorChangedListener,
44 | View.OnClickListener, ViewTreeObserver.OnGlobalLayoutListener {
45 |
46 | private ColorPickerView mColorPicker;
47 |
48 | private ColorPickerPanelView mOldColor;
49 | private ColorPickerPanelView mNewColor;
50 |
51 | private EditText mHexVal;
52 | private boolean mHexValueEnabled = false;
53 | private ColorStateList mHexDefaultTextColor;
54 |
55 | private OnColorChangedListener mListener;
56 | private int mOrientation;
57 | private View mLayout;
58 |
59 | @Override
60 | public void onGlobalLayout() {
61 | if (getContext().getResources().getConfiguration().orientation != mOrientation) {
62 | final int oldcolor = mOldColor.getColor();
63 | final int newcolor = mNewColor.getColor();
64 | mLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
65 | setUp(oldcolor);
66 | mNewColor.setColor(newcolor);
67 | mColorPicker.setColor(newcolor);
68 | }
69 | }
70 |
71 | public interface OnColorChangedListener {
72 | public void onColorChanged(int color);
73 | }
74 |
75 | public ColorPickerDialog(Context context, int initialColor) {
76 | super(context);
77 |
78 | init(initialColor);
79 | }
80 |
81 | private void init(int color) {
82 | // To fight color banding.
83 | getWindow().setFormat(PixelFormat.RGBA_8888);
84 |
85 | setUp(color);
86 |
87 | }
88 |
89 | private void setUp(int color) {
90 |
91 | LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
92 |
93 | mLayout = inflater.inflate(R.layout.dialog_color_picker, null);
94 | mLayout.getViewTreeObserver().addOnGlobalLayoutListener(this);
95 |
96 | mOrientation = getContext().getResources().getConfiguration().orientation;
97 | setContentView(mLayout);
98 |
99 | setTitle(R.string.dialog_color_picker);
100 |
101 | mColorPicker = (ColorPickerView) mLayout.findViewById(R.id.color_picker_view);
102 | mOldColor = (ColorPickerPanelView) mLayout.findViewById(R.id.old_color_panel);
103 | mNewColor = (ColorPickerPanelView) mLayout.findViewById(R.id.new_color_panel);
104 |
105 | mHexVal = (EditText) mLayout.findViewById(R.id.hex_val);
106 | mHexVal.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
107 | mHexDefaultTextColor = mHexVal.getTextColors();
108 |
109 | mHexVal.setOnEditorActionListener(new TextView.OnEditorActionListener() {
110 |
111 | @Override
112 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
113 | if (actionId == EditorInfo.IME_ACTION_DONE) {
114 | InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
115 | imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
116 | String s = mHexVal.getText().toString();
117 | if (s.length() > 5 || s.length() < 10) {
118 | try {
119 | int c = ColorPickerPreference.convertToColorInt(s.toString());
120 | mColorPicker.setColor(c, true);
121 | mHexVal.setTextColor(mHexDefaultTextColor);
122 | } catch (IllegalArgumentException e) {
123 | mHexVal.setTextColor(Color.RED);
124 | }
125 | } else {
126 | mHexVal.setTextColor(Color.RED);
127 | }
128 | return true;
129 | }
130 | return false;
131 | }
132 | });
133 |
134 | ((LinearLayout) mOldColor.getParent()).setPadding(
135 | Math.round(mColorPicker.getDrawingOffset()),
136 | 0,
137 | Math.round(mColorPicker.getDrawingOffset()),
138 | 0
139 | );
140 |
141 | mOldColor.setOnClickListener(this);
142 | mNewColor.setOnClickListener(this);
143 | mColorPicker.setOnColorChangedListener(this);
144 | mOldColor.setColor(color);
145 | mColorPicker.setColor(color, true);
146 |
147 | }
148 |
149 | @Override
150 | public void onColorChanged(int color) {
151 |
152 | mNewColor.setColor(color);
153 |
154 | if (mHexValueEnabled)
155 | updateHexValue(color);
156 |
157 | /*
158 | if (mListener != null) {
159 | mListener.onColorChanged(color);
160 | }
161 | */
162 |
163 | }
164 |
165 | public void setHexValueEnabled(boolean enable) {
166 | mHexValueEnabled = enable;
167 | if (enable) {
168 | mHexVal.setVisibility(View.VISIBLE);
169 | updateHexLengthFilter();
170 | updateHexValue(getColor());
171 | } else
172 | mHexVal.setVisibility(View.GONE);
173 | }
174 |
175 | public boolean getHexValueEnabled() {
176 | return mHexValueEnabled;
177 | }
178 |
179 | private void updateHexLengthFilter() {
180 | if (getAlphaSliderVisible())
181 | mHexVal.setFilters(new InputFilter[]{new InputFilter.LengthFilter(9)});
182 | else
183 | mHexVal.setFilters(new InputFilter[]{new InputFilter.LengthFilter(7)});
184 | }
185 |
186 | private void updateHexValue(int color) {
187 | if (getAlphaSliderVisible()) {
188 | mHexVal.setText(ColorPickerPreference.convertToARGB(color).toUpperCase(Locale.getDefault()));
189 | } else {
190 | mHexVal.setText(ColorPickerPreference.convertToRGB(color).toUpperCase(Locale.getDefault()));
191 | }
192 | mHexVal.setTextColor(mHexDefaultTextColor);
193 | }
194 |
195 | public void setAlphaSliderVisible(boolean visible) {
196 | mColorPicker.setAlphaSliderVisible(visible);
197 | if (mHexValueEnabled) {
198 | updateHexLengthFilter();
199 | updateHexValue(getColor());
200 | }
201 | }
202 |
203 | public boolean getAlphaSliderVisible() {
204 | return mColorPicker.getAlphaSliderVisible();
205 | }
206 |
207 | /**
208 | * Set a OnColorChangedListener to get notified when the color
209 | * selected by the user has changed.
210 | *
211 | * @param listener
212 | */
213 | public void setOnColorChangedListener(OnColorChangedListener listener) {
214 | mListener = listener;
215 | }
216 |
217 | public int getColor() {
218 | return mColorPicker.getColor();
219 | }
220 |
221 | @Override
222 | public void onClick(View v) {
223 | if (v.getId() == R.id.new_color_panel) {
224 | if (mListener != null) {
225 | mListener.onColorChanged(mNewColor.getColor());
226 | }
227 | }
228 | dismiss();
229 | }
230 |
231 | @Override
232 | public Bundle onSaveInstanceState() {
233 | Bundle state = super.onSaveInstanceState();
234 | state.putInt("old_color", mOldColor.getColor());
235 | state.putInt("new_color", mNewColor.getColor());
236 | return state;
237 | }
238 |
239 | @Override
240 | public void onRestoreInstanceState(Bundle savedInstanceState) {
241 | super.onRestoreInstanceState(savedInstanceState);
242 | mOldColor.setColor(savedInstanceState.getInt("old_color"));
243 | mColorPicker.setColor(savedInstanceState.getInt("new_color"), true);
244 | }
245 | }
246 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerPanelView.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2010 Daniel Nilsson
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.graphics.Canvas;
21 | import android.graphics.Paint;
22 | import android.graphics.RectF;
23 | import android.util.AttributeSet;
24 | import android.view.View;
25 |
26 | /**
27 | * This class draws a panel which which will be filled with a color which can be set.
28 | * It can be used to show the currently selected color which you will get from
29 | * the {@link ColorPickerView}.
30 | *
31 | * @author Daniel Nilsson
32 | */
33 | public class ColorPickerPanelView extends View {
34 |
35 | /**
36 | * The width in pixels of the border
37 | * surrounding the color panel.
38 | */
39 | private final static float BORDER_WIDTH_PX = 1;
40 |
41 | private float mDensity = 1f;
42 |
43 | private int mBorderColor = 0xff6E6E6E;
44 | private int mColor = 0xff000000;
45 |
46 | private Paint mBorderPaint;
47 | private Paint mColorPaint;
48 |
49 | private RectF mDrawingRect;
50 | private RectF mColorRect;
51 |
52 | private AlphaPatternDrawable mAlphaPattern;
53 |
54 |
55 | public ColorPickerPanelView(Context context) {
56 | this(context, null);
57 | }
58 |
59 | public ColorPickerPanelView(Context context, AttributeSet attrs) {
60 | this(context, attrs, 0);
61 | }
62 |
63 | public ColorPickerPanelView(Context context, AttributeSet attrs, int defStyle) {
64 | super(context, attrs, defStyle);
65 | init();
66 | }
67 |
68 | private void init() {
69 | mBorderPaint = new Paint();
70 | mColorPaint = new Paint();
71 | mDensity = getContext().getResources().getDisplayMetrics().density;
72 | }
73 |
74 |
75 | @Override
76 | protected void onDraw(Canvas canvas) {
77 |
78 | final RectF rect = mColorRect;
79 |
80 | if (BORDER_WIDTH_PX > 0) {
81 | mBorderPaint.setColor(mBorderColor);
82 | canvas.drawRect(mDrawingRect, mBorderPaint);
83 | }
84 |
85 | if (mAlphaPattern != null) {
86 | mAlphaPattern.draw(canvas);
87 | }
88 |
89 | mColorPaint.setColor(mColor);
90 |
91 | canvas.drawRect(rect, mColorPaint);
92 | }
93 |
94 | @Override
95 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
96 |
97 | int width = MeasureSpec.getSize(widthMeasureSpec);
98 | int height = MeasureSpec.getSize(heightMeasureSpec);
99 |
100 | setMeasuredDimension(width, height);
101 | }
102 |
103 | @Override
104 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
105 | super.onSizeChanged(w, h, oldw, oldh);
106 |
107 | mDrawingRect = new RectF();
108 | mDrawingRect.left = getPaddingLeft();
109 | mDrawingRect.right = w - getPaddingRight();
110 | mDrawingRect.top = getPaddingTop();
111 | mDrawingRect.bottom = h - getPaddingBottom();
112 |
113 | setUpColorRect();
114 |
115 | }
116 |
117 | private void setUpColorRect() {
118 | final RectF dRect = mDrawingRect;
119 |
120 | float left = dRect.left + BORDER_WIDTH_PX;
121 | float top = dRect.top + BORDER_WIDTH_PX;
122 | float bottom = dRect.bottom - BORDER_WIDTH_PX;
123 | float right = dRect.right - BORDER_WIDTH_PX;
124 |
125 | mColorRect = new RectF(left, top, right, bottom);
126 |
127 | mAlphaPattern = new AlphaPatternDrawable((int) (5 * mDensity));
128 |
129 | mAlphaPattern.setBounds(
130 | Math.round(mColorRect.left),
131 | Math.round(mColorRect.top),
132 | Math.round(mColorRect.right),
133 | Math.round(mColorRect.bottom)
134 | );
135 |
136 | }
137 |
138 | /**
139 | * Set the color that should be shown by this view.
140 | *
141 | * @param color
142 | */
143 | public void setColor(int color) {
144 | mColor = color;
145 | invalidate();
146 | }
147 |
148 | /**
149 | * Get the color currently show by this view.
150 | *
151 | * @return
152 | */
153 | public int getColor() {
154 | return mColor;
155 | }
156 |
157 | /**
158 | * Set the color of the border surrounding the panel.
159 | *
160 | * @param color
161 | */
162 | public void setBorderColor(int color) {
163 | mBorderColor = color;
164 | invalidate();
165 | }
166 |
167 | /**
168 | * Get the color of the border surrounding the panel.
169 | */
170 | public int getBorderColor() {
171 | return mBorderColor;
172 | }
173 |
174 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/java/net/margaritov/preference/colorpicker/ColorPickerPreference.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Sergey Margaritov
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package net.margaritov.preference.colorpicker;
18 |
19 | import android.content.Context;
20 | import android.content.res.TypedArray;
21 | import android.graphics.Bitmap;
22 | import android.graphics.Bitmap.Config;
23 | import android.graphics.Color;
24 | import android.os.Bundle;
25 | import android.os.Parcel;
26 | import android.os.Parcelable;
27 | import android.preference.Preference;
28 | import android.util.AttributeSet;
29 | import android.view.View;
30 | import android.widget.ImageView;
31 | import android.widget.LinearLayout;
32 |
33 | /**
34 | * A preference type that allows a user to choose a time
35 | *
36 | * @author Sergey Margaritov
37 | */
38 | public class ColorPickerPreference
39 | extends
40 | Preference
41 | implements
42 | Preference.OnPreferenceClickListener,
43 | ColorPickerDialog.OnColorChangedListener {
44 |
45 | View mView;
46 | ColorPickerDialog mDialog;
47 | private int mValue = Color.BLACK;
48 | private float mDensity = 0;
49 | private boolean mAlphaSliderEnabled = false;
50 | private boolean mHexValueEnabled = false;
51 |
52 | public ColorPickerPreference(Context context) {
53 | super(context);
54 | init(context, null);
55 | }
56 |
57 | public ColorPickerPreference(Context context, AttributeSet attrs) {
58 | super(context, attrs);
59 | init(context, attrs);
60 | }
61 |
62 | public ColorPickerPreference(Context context, AttributeSet attrs, int defStyle) {
63 | super(context, attrs, defStyle);
64 | init(context, attrs);
65 | }
66 |
67 | /**Method edited by
68 | * @author Anna Berkovitch
69 | * added functionality to accept hex string as defaultValue
70 | * and to properly persist resources reference string, such as @color/someColor
71 | * previously persisted 0*/
72 | @Override
73 | protected Object onGetDefaultValue(TypedArray a, int index) {
74 | int colorInt;
75 | String mHexDefaultValue = a.getString(index);
76 | if (mHexDefaultValue != null && mHexDefaultValue.startsWith("#")) {
77 | colorInt = convertToColorInt(mHexDefaultValue);
78 | return colorInt;
79 |
80 | } else {
81 | return a.getColor(index, Color.BLACK);
82 | }
83 | }
84 |
85 | @Override
86 | protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
87 | onColorChanged(restoreValue ? getPersistedInt(mValue) : (Integer) defaultValue);
88 | }
89 |
90 | private void init(Context context, AttributeSet attrs) {
91 | mDensity = getContext().getResources().getDisplayMetrics().density;
92 | setOnPreferenceClickListener(this);
93 | if (attrs != null) {
94 | mAlphaSliderEnabled = attrs.getAttributeBooleanValue(null, "alphaSlider", false);
95 | mHexValueEnabled = attrs.getAttributeBooleanValue(null, "hexValue", false);
96 | }
97 | }
98 |
99 | @Override
100 | protected void onBindView(View view) {
101 | super.onBindView(view);
102 | mView = view;
103 | setPreviewColor();
104 | }
105 |
106 | private void setPreviewColor() {
107 | if (mView == null) return;
108 | ImageView iView = new ImageView(getContext());
109 | LinearLayout widgetFrameView = ((LinearLayout) mView.findViewById(android.R.id.widget_frame));
110 | if (widgetFrameView == null) return;
111 | widgetFrameView.setVisibility(View.VISIBLE);
112 | widgetFrameView.setPadding(
113 | widgetFrameView.getPaddingLeft(),
114 | widgetFrameView.getPaddingTop(),
115 | (int) (mDensity * 8),
116 | widgetFrameView.getPaddingBottom()
117 | );
118 | // remove already create preview image
119 | int count = widgetFrameView.getChildCount();
120 | if (count > 0) {
121 | widgetFrameView.removeViews(0, count);
122 | }
123 | widgetFrameView.addView(iView);
124 | widgetFrameView.setMinimumWidth(0);
125 | iView.setBackgroundDrawable(new AlphaPatternDrawable((int) (5 * mDensity)));
126 | iView.setImageBitmap(getPreviewBitmap());
127 | }
128 |
129 | private Bitmap getPreviewBitmap() {
130 | int d = (int) (mDensity * 31); //30dip
131 | int color = mValue;
132 | Bitmap bm = Bitmap.createBitmap(d, d, Config.ARGB_8888);
133 | int w = bm.getWidth();
134 | int h = bm.getHeight();
135 | int c = color;
136 | for (int i = 0; i < w; i++) {
137 | for (int j = i; j < h; j++) {
138 | c = (i <= 1 || j <= 1 || i >= w - 2 || j >= h - 2) ? Color.GRAY : color;
139 | bm.setPixel(i, j, c);
140 | if (i != j) {
141 | bm.setPixel(j, i, c);
142 | }
143 | }
144 | }
145 |
146 | return bm;
147 | }
148 |
149 | @Override
150 | public void onColorChanged(int color) {
151 | if (isPersistent()) {
152 | persistInt(color);
153 | }
154 | mValue = color;
155 | setPreviewColor();
156 | try {
157 | getOnPreferenceChangeListener().onPreferenceChange(this, color);
158 | } catch (NullPointerException e) {
159 |
160 | }
161 | }
162 |
163 | public boolean onPreferenceClick(Preference preference) {
164 | showDialog(null);
165 | return false;
166 | }
167 |
168 | protected void showDialog(Bundle state) {
169 | mDialog = new ColorPickerDialog(getContext(), mValue);
170 | mDialog.setOnColorChangedListener(this);
171 | if (mAlphaSliderEnabled) {
172 | mDialog.setAlphaSliderVisible(true);
173 | }
174 | if (mHexValueEnabled) {
175 | mDialog.setHexValueEnabled(true);
176 | }
177 | if (state != null) {
178 | mDialog.onRestoreInstanceState(state);
179 | }
180 | mDialog.show();
181 | }
182 |
183 | /**
184 | * Toggle Alpha Slider visibility (by default it's disabled)
185 | *
186 | * @param enable
187 | */
188 | public void setAlphaSliderEnabled(boolean enable) {
189 | mAlphaSliderEnabled = enable;
190 | }
191 |
192 | /**
193 | * Toggle Hex Value visibility (by default it's disabled)
194 | *
195 | * @param enable
196 | */
197 | public void setHexValueEnabled(boolean enable) {
198 | mHexValueEnabled = enable;
199 | }
200 |
201 | /**
202 | * For custom purposes. Not used by ColorPickerPreferrence
203 | *
204 | * @param color
205 | * @author Unknown
206 | */
207 | public static String convertToARGB(int color) {
208 | String alpha = Integer.toHexString(Color.alpha(color));
209 | String red = Integer.toHexString(Color.red(color));
210 | String green = Integer.toHexString(Color.green(color));
211 | String blue = Integer.toHexString(Color.blue(color));
212 |
213 | if (alpha.length() == 1) {
214 | alpha = "0" + alpha;
215 | }
216 |
217 | if (red.length() == 1) {
218 | red = "0" + red;
219 | }
220 |
221 | if (green.length() == 1) {
222 | green = "0" + green;
223 | }
224 |
225 | if (blue.length() == 1) {
226 | blue = "0" + blue;
227 | }
228 |
229 | return "#" + alpha + red + green + blue;
230 | }
231 |
232 | /**
233 | * Method currently used by onGetDefaultValue method to
234 | * convert hex string provided in android:defaultValue to color integer.
235 | *
236 | * @param color
237 | * @return A string representing the hex value of color,
238 | * without the alpha value
239 | * @author Charles Rosaaen
240 | */
241 | public static String convertToRGB(int color) {
242 | String red = Integer.toHexString(Color.red(color));
243 | String green = Integer.toHexString(Color.green(color));
244 | String blue = Integer.toHexString(Color.blue(color));
245 |
246 | if (red.length() == 1) {
247 | red = "0" + red;
248 | }
249 |
250 | if (green.length() == 1) {
251 | green = "0" + green;
252 | }
253 |
254 | if (blue.length() == 1) {
255 | blue = "0" + blue;
256 | }
257 |
258 | return "#" + red + green + blue;
259 | }
260 |
261 | /**
262 | * For custom purposes. Not used by ColorPickerPreferrence
263 | *
264 | * @param argb
265 | * @throws NumberFormatException
266 | * @author Unknown
267 | */
268 | public static int convertToColorInt(String argb) throws IllegalArgumentException {
269 |
270 | if (!argb.startsWith("#")) {
271 | argb = "#" + argb;
272 | }
273 |
274 | return Color.parseColor(argb);
275 | }
276 |
277 | @Override
278 | protected Parcelable onSaveInstanceState() {
279 | final Parcelable superState = super.onSaveInstanceState();
280 | if (mDialog == null || !mDialog.isShowing()) {
281 | return superState;
282 | }
283 |
284 | final SavedState myState = new SavedState(superState);
285 | myState.dialogBundle = mDialog.onSaveInstanceState();
286 | return myState;
287 | }
288 |
289 | @Override
290 | protected void onRestoreInstanceState(Parcelable state) {
291 | if (state == null || !(state instanceof SavedState)) {
292 | // Didn't save state for us in onSaveInstanceState
293 | super.onRestoreInstanceState(state);
294 | return;
295 | }
296 |
297 | SavedState myState = (SavedState) state;
298 | super.onRestoreInstanceState(myState.getSuperState());
299 | showDialog(myState.dialogBundle);
300 | }
301 |
302 | private static class SavedState extends BaseSavedState {
303 | Bundle dialogBundle;
304 |
305 | public SavedState(Parcel source) {
306 | super(source);
307 | dialogBundle = source.readBundle();
308 | }
309 |
310 | @Override
311 | public void writeToParcel(Parcel dest, int flags) {
312 | super.writeToParcel(dest, flags);
313 | dest.writeBundle(dialogBundle);
314 | }
315 |
316 | public SavedState(Parcelable superState) {
317 | super(superState);
318 | }
319 |
320 | @SuppressWarnings("unused")
321 | public static final Parcelable.Creator CREATOR =
322 | new Parcelable.Creator() {
323 | public SavedState createFromParcel(Parcel in) {
324 | return new SavedState(in);
325 | }
326 |
327 | public SavedState[] newArray(int size) {
328 | return new SavedState[size];
329 | }
330 | };
331 | }
332 | }
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/res/layout-land/dialog_color_picker.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
24 |
25 |
31 |
32 |
37 |
38 |
48 |
49 |
59 |
60 |
65 |
66 |
74 |
75 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/res/layout/dialog_color_picker.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
24 |
25 |
31 |
32 |
39 |
40 |
46 |
47 |
58 |
59 |
60 |
65 |
66 |
71 |
72 |
80 |
81 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/libs/ColorPickerPreference/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Color Picker
5 | Press on Color to apply
6 |
7 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/rijul/Android/Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
14 |
15 |
19 |
20 |
21 |
25 |
26 |
27 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
56 |
57 |
58 |
59 |
60 |
61 |
65 |
66 |
67 |
68 |
69 |
70 |
73 |
76 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | me.rijul.knockcode.XposedMod
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package me.rijul.knockcode;
2 |
3 | import android.app.ActionBar;
4 | import android.app.Activity;
5 | import android.app.AlertDialog;
6 | import android.app.Dialog;
7 | import android.content.DialogInterface;
8 | import android.os.Bundle;
9 | import android.preference.Preference;
10 | import android.preference.PreferenceFragment;
11 | import android.preference.PreferenceScreen;
12 | import android.view.Gravity;
13 | import android.view.MenuItem;
14 | import android.widget.TextView;
15 |
16 | /**
17 | * Created by rijul on 25/3/16.
18 | */
19 | public class AboutActivity extends Activity {
20 | @Override
21 | public void onCreate(Bundle savedInstanceState) {
22 | super.onCreate(savedInstanceState);
23 | setContentView(R.layout.main);
24 | ActionBar actionBar = getActionBar();
25 | actionBar.setDisplayHomeAsUpEnabled(true);
26 | getFragmentManager().beginTransaction().replace(R.id.fragment_container, new AboutFragment()).commit();
27 | CustomLogger.log(this, "AboutActivity", "App", "Opened About", null, -1);
28 | }
29 |
30 | @Override
31 | public boolean onOptionsItemSelected(MenuItem item) {
32 | switch (item.getItemId()) {
33 | case android.R.id.home:
34 | finish();
35 | return true;
36 | default:
37 | return super.onOptionsItemSelected(item);
38 | }
39 | }
40 |
41 | public static class AboutFragment extends PreferenceFragment {
42 | @Override
43 | public void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | addPreferencesFromResource(R.xml.about);
46 | }
47 |
48 | @Override
49 | public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
50 | String key = preference.getKey();
51 | if (key==null)
52 | return false;
53 | else if (key.equals(Utils.ABOUT_DISCLAIMER)) {
54 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
55 | builder.setTitle(R.string.about_disclaimer_title);
56 | final TextView message = new TextView(getActivity());
57 | message.setText(R.string.about_disclaimer_message);
58 | message.setGravity(Gravity.CENTER);
59 | builder.setView(message);
60 | builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
61 | public void onClick(DialogInterface dialog, int id) {
62 | dialog.dismiss();
63 | }
64 | });
65 | Dialog dialog = builder.create();
66 | dialog.show();
67 | return true;
68 | }
69 | return false;
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/AppearAnimationCreator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 |
17 | package me.rijul.knockcode;
18 |
19 | import android.view.animation.Interpolator;
20 |
21 | /**
22 | * An interface which can create animations when starting an appear animation with
23 | * {@link com.android.keyguard.AppearAnimationUtils}
24 | */
25 | public interface AppearAnimationCreator {
26 | void createAnimation(T animatedObject, long delay, long duration,
27 | float translationY, boolean appearing, Interpolator interpolator,
28 | Runnable finishListener);
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/AppearAnimationUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 |
17 | package me.rijul.knockcode;
18 |
19 | import android.content.Context;
20 | import android.content.res.Resources;
21 | import android.view.View;
22 | import android.view.animation.AnimationUtils;
23 | import android.view.animation.Interpolator;
24 |
25 | /**
26 | * A class to make nice appear transitions for views in a tabular layout.
27 | */
28 | public class AppearAnimationUtils implements AppearAnimationCreator {
29 |
30 | public static final long DEFAULT_APPEAR_DURATION = 220;
31 |
32 | private final Interpolator mInterpolator;
33 | private float mStartTranslation;
34 | private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
35 | protected final float mDelayScale;
36 | private long mDuration;
37 | protected boolean mScaleTranslationWithRow;
38 | protected boolean mAppearing;
39 |
40 | public AppearAnimationUtils(Context ctx) {
41 | this(ctx, DEFAULT_APPEAR_DURATION,
42 | 1.0f, 1.0f,
43 | AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
44 | }
45 |
46 | public AppearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
47 | float delayScaleFactor, Interpolator interpolator) {
48 | mInterpolator = interpolator;
49 | Resources res = Utils.getResourcesForPackage(ctx, ctx.getPackageName());
50 | mStartTranslation = res.getDimensionPixelOffset(res.
51 | getIdentifier("appear_y_translation_start", "dimen", ctx.getPackageName())) * translationScaleFactor;
52 | //mStartTranslation = 32 * translationScaleFactor;
53 | mDelayScale = delayScaleFactor;
54 | mDuration = duration;
55 | mScaleTranslationWithRow = false;
56 | mAppearing = true;
57 | }
58 |
59 | public void setDuration(int duration) {
60 | mDuration = duration;
61 | }
62 |
63 | public void startAnimation(View[][] objects, final Runnable finishListener) {
64 | startAnimation(objects, finishListener, this);
65 | }
66 |
67 | public void startAnimation(View[] objects, final Runnable finishListener) {
68 | startAnimation(objects, finishListener, this);
69 | }
70 |
71 | public void startAnimation(T[][] objects, final Runnable finishListener,
72 | AppearAnimationCreator creator) {
73 | AppearAnimationProperties properties = getDelays(objects);
74 | startAnimations(properties, objects, finishListener, creator);
75 | }
76 |
77 | public void startAnimation(T[] objects, final Runnable finishListener,
78 | AppearAnimationCreator creator) {
79 | AppearAnimationProperties properties = getDelays(objects);
80 | startAnimations(properties, objects, finishListener, creator);
81 | }
82 |
83 | private void startAnimations(AppearAnimationProperties properties, T[] objects,
84 | final Runnable finishListener, AppearAnimationCreator creator) {
85 | if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
86 | finishListener.run();
87 | return;
88 | }
89 | for (int row = 0; row < properties.delays.length; row++) {
90 | long[] columns = properties.delays[row];
91 | long delay = columns[0];
92 | Runnable endRunnable = null;
93 | if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == 0) {
94 | endRunnable = finishListener;
95 | }
96 | creator.createAnimation(objects[row], delay, mDuration,
97 | mStartTranslation, true /* appearing */, mInterpolator, endRunnable);
98 | }
99 | }
100 |
101 | private void startAnimations(AppearAnimationProperties properties, T[][] objects,
102 | final Runnable finishListener, AppearAnimationCreator creator) {
103 | if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
104 | finishListener.run();
105 | return;
106 | }
107 | for (int row = 0; row < properties.delays.length; row++) {
108 | long[] columns = properties.delays[row];
109 | float translation = mScaleTranslationWithRow
110 | ? (float) (Math.pow((properties.delays.length - row), 2)
111 | / properties.delays.length * mStartTranslation)
112 | : mStartTranslation;
113 | for (int col = 0; col < columns.length; col++) {
114 | long delay = columns[col];
115 | Runnable endRunnable = null;
116 | if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) {
117 | endRunnable = finishListener;
118 | }
119 | creator.createAnimation(objects[row][col], delay, mDuration,
120 | mAppearing ? translation : -translation,
121 | mAppearing, mInterpolator, endRunnable);
122 | }
123 | }
124 | }
125 |
126 | private AppearAnimationProperties getDelays(T[] items) {
127 | long maxDelay = -1;
128 | mProperties.maxDelayColIndex = -1;
129 | mProperties.maxDelayRowIndex = -1;
130 | mProperties.delays = new long[items.length][];
131 | for (int row = 0; row < items.length; row++) {
132 | mProperties.delays[row] = new long[1];
133 | long delay = calculateDelay(row, 0);
134 | mProperties.delays[row][0] = delay;
135 | if (items[row] != null && delay > maxDelay) {
136 | maxDelay = delay;
137 | mProperties.maxDelayColIndex = 0;
138 | mProperties.maxDelayRowIndex = row;
139 | }
140 | }
141 | return mProperties;
142 | }
143 |
144 | private AppearAnimationProperties getDelays(T[][] items) {
145 | long maxDelay = -1;
146 | mProperties.maxDelayColIndex = -1;
147 | mProperties.maxDelayRowIndex = -1;
148 | mProperties.delays = new long[items.length][];
149 | for (int row = 0; row < items.length; row++) {
150 | T[] columns = items[row];
151 | mProperties.delays[row] = new long[columns.length];
152 | for (int col = 0; col < columns.length; col++) {
153 | long delay = calculateDelay(row, col);
154 | mProperties.delays[row][col] = delay;
155 | if (items[row][col] != null && delay > maxDelay) {
156 | maxDelay = delay;
157 | mProperties.maxDelayColIndex = col;
158 | mProperties.maxDelayRowIndex = row;
159 | }
160 | }
161 | }
162 | return mProperties;
163 | }
164 |
165 | protected long calculateDelay(int row, int col) {
166 | return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale);
167 | }
168 |
169 | public Interpolator getInterpolator() {
170 | return mInterpolator;
171 | }
172 |
173 | public float getStartTranslation() {
174 | return mStartTranslation;
175 | }
176 |
177 | @Override
178 | public void createAnimation(View view, long delay, long duration, float translationY,
179 | boolean appearing, Interpolator interpolator, Runnable endRunnable) {
180 | if (view != null) {
181 | view.setAlpha(appearing ? 0f : 1.0f);
182 | view.setTranslationY(appearing ? translationY : 0);
183 | view.animate()
184 | .alpha(appearing ? 1f : 0f)
185 | .translationY(appearing ? 0 : translationY)
186 | .setInterpolator(interpolator)
187 | .setDuration(duration)
188 | .setStartDelay(delay);
189 | if (view.hasOverlappingRendering()) {
190 | view.animate().withLayer();
191 | }
192 | if (endRunnable != null) {
193 | view.animate().withEndAction(endRunnable);
194 | }
195 | }
196 | }
197 |
198 | public class AppearAnimationProperties {
199 | public long[][] delays;
200 | public int maxDelayRowIndex;
201 | public int maxDelayColIndex;
202 | }
203 | }
204 |
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/DisappearAnimationUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2014 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License
15 | */
16 |
17 | package me.rijul.knockcode;
18 |
19 | import android.content.Context;
20 | import android.view.animation.AnimationUtils;
21 | import android.view.animation.Interpolator;
22 |
23 | /**
24 | * A class to make nice disappear transitions for views in a tabular layout.
25 | */
26 | public class DisappearAnimationUtils extends AppearAnimationUtils {
27 |
28 | public DisappearAnimationUtils(Context ctx) {
29 | this(ctx, DEFAULT_APPEAR_DURATION,
30 | 1.0f, 1.0f,
31 | AnimationUtils.loadInterpolator(ctx, android.R.interpolator.linear_out_slow_in));
32 | }
33 |
34 | public DisappearAnimationUtils(Context ctx, long duration, float translationScaleFactor,
35 | float delayScaleFactor, Interpolator interpolator) {
36 | super(ctx, duration, translationScaleFactor, delayScaleFactor, interpolator);
37 | mScaleTranslationWithRow = true;
38 | mAppearing = false;
39 | }
40 |
41 | protected long calculateDelay(int row, int col) {
42 | return (long) ((row * 60 + col * (Math.pow(row, 0.4) + 0.4) * 10) * mDelayScale);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/Grid.java:
--------------------------------------------------------------------------------
1 | package me.rijul.knockcode;
2 |
3 | /**
4 | * Created by rijul on 24/12/15.
5 | */
6 | public class Grid {
7 | public int numberOfColumns;
8 | public int numberOfRows;
9 |
10 | public Grid(int nC, int nR) {
11 | numberOfColumns = nC;
12 | numberOfRows = nR;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/KillReceiver.java:
--------------------------------------------------------------------------------
1 | package me.rijul.knockcode;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | /**
8 | * Created by rijul on 25/3/16.
9 | */
10 | public class KillReceiver extends BroadcastReceiver {
11 | @Override
12 | public void onReceive(Context context, Intent intent) {
13 | new SettingsHelper(context).putBoolean(Utils.SETTINGS_SWITCH, false);
14 | context.sendBroadcast(new Intent(BuildConfig.APPLICATION_ID + ".DEAD"));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/me/rijul/knockcode/LockButtonView.java:
--------------------------------------------------------------------------------
1 | package me.rijul.knockcode;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.os.Handler;
6 | import android.util.AttributeSet;
7 | import android.util.TypedValue;
8 | import android.view.MotionEvent;
9 | import android.view.View;
10 | import android.view.ViewConfiguration;
11 | import android.view.ViewGroup;
12 | import android.widget.Button;
13 | import android.widget.LinearLayout;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | public class LockButtonView extends LinearLayout implements View.OnLongClickListener, View.OnTouchListener {
18 | private ArrayList mEnteredCode = new ArrayList<>();
19 |
20 | final Handler mHandler = new Handler();
21 | Runnable mLongPressed = new Runnable() {
22 | @Override
23 | public void run() {
24 | mLongPress = true;
25 | if (mLongClickListener!=null)
26 | mLongClickListener.onLongClick(LockButtonView.this);
27 | }
28 | };
29 | private boolean mLongPress = false;
30 |
31 | public interface OnLongPressCompletedListener {
32 | void onLongPressCompleted();
33 | }
34 | private OnLongPressCompletedListener onLongPressCompletedListener;
35 | public void setOnLongPressCompletedListener(OnLongPressCompletedListener listener) {
36 | onLongPressCompletedListener = listener;
37 | }
38 |
39 | @Override
40 | public boolean onTouch(View v, MotionEvent event) {
41 | if (event.getActionMasked() == MotionEvent.ACTION_DOWN)
42 | mHandler.postDelayed(mLongPressed, ViewConfiguration.getLongPressTimeout());
43 | else if (event.getActionMasked() == MotionEvent.ACTION_UP) {
44 | if (mLongPress) {
45 | if (onLongPressCompletedListener != null)
46 | onLongPressCompletedListener.onLongPressCompleted();
47 | mLongPress = false;
48 | return false;
49 | }
50 | mHandler.removeCallbacks(mLongPressed);
51 | mEnteredCode.add(v.getId());
52 | if (mListener != null)
53 | mListener.onPositionTapped((Button) v, mEnteredCode);
54 | }
55 | return false;
56 | }
57 |
58 | public enum Mode {
59 | Ready, Correct, Incorrect, Disabled
60 | }
61 |
62 | public static int KNOCK_CODE_MAX_SIZE = 12+1, KNOCK_CODE_MIN_SIZE = 3;
63 | public static int GRID_MIN_SIZE = 2, GRID_MAX_SIZE = 5;
64 |
65 | private Grid mPatternSize = new Grid(2,2);
66 | private OnPositionTappedListener mListener;
67 | private OnLongClickListener mLongClickListener;
68 |
69 | private List