├── .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 | 14 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Knock Code with Custom Shortcuts 2 | ![Knock Code (Logo)](https://raw.githubusercontent.com/Rijul-Ahuja/Xposed-Knock-Code/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png) 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 | ![Knock Code Entry](https://raw.githubusercontent.com/Rijul-Ahuja/Xposed-Knock-Code/master/screenShots/lockScreen.jpg) 20 | ![Custom Shortcuts](https://raw.githubusercontent.com/Rijul-Ahuja/Xposed-Knock-Code/master/screenShots/customShortcutSelector.jpg) 21 | ![Settings](https://raw.githubusercontent.com/Rijul-Ahuja/Xposed-Knock-Code/master/screenShots/someSettings.jpg) 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