[
  {
    "path": ".gitignore",
    "content": "# Created by .ignore support plugin (hsz.mobi)\n### Android template\n# Built application files\n*.apk\n*.ap_\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Intellij\n*.iml\n.idea/workspace.xml\n.idea/tasks.xml\n.idea/gradle.xml\n.idea/dictionaries\n.idea/libraries\n\n# Keystore files\n*.jks\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n# Google Services (e.g. APIs or Firebase)\ngoogle-services.json\n\n# Freeline\nfreeline.py\nfreeline/\nfreeline_project_description.json\n\n"
  },
  {
    "path": ".idea/compiler.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"CompilerConfiguration\">\n    <resourceExtensions />\n    <wildcardResourcePatterns>\n      <entry name=\"!?*.java\" />\n      <entry name=\"!?*.form\" />\n      <entry name=\"!?*.class\" />\n      <entry name=\"!?*.groovy\" />\n      <entry name=\"!?*.scala\" />\n      <entry name=\"!?*.flex\" />\n      <entry name=\"!?*.kt\" />\n      <entry name=\"!?*.clj\" />\n    </wildcardResourcePatterns>\n    <annotationProcessing>\n      <profile default=\"true\" name=\"Default\" enabled=\"false\">\n        <processorPath useClasspath=\"true\" />\n      </profile>\n    </annotationProcessing>\n  </component>\n</project>"
  },
  {
    "path": ".idea/copyright/profiles_settings.xml",
    "content": "<component name=\"CopyrightManager\">\n  <settings default=\"\" />\n</component>"
  },
  {
    "path": ".idea/misc.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"EntryPointsManager\">\n    <entry_points version=\"2.0\" />\n  </component>\n  <component name=\"NullableNotNullManager\">\n    <option name=\"myDefaultNullable\" value=\"android.support.annotation.Nullable\" />\n    <option name=\"myDefaultNotNull\" value=\"android.support.annotation.NonNull\" />\n    <option name=\"myNullables\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.Nullable\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nullable\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.Nullable\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.Nullable\" />\n        </list>\n      </value>\n    </option>\n    <option name=\"myNotNulls\">\n      <value>\n        <list size=\"4\">\n          <item index=\"0\" class=\"java.lang.String\" itemvalue=\"org.jetbrains.annotations.NotNull\" />\n          <item index=\"1\" class=\"java.lang.String\" itemvalue=\"javax.annotation.Nonnull\" />\n          <item index=\"2\" class=\"java.lang.String\" itemvalue=\"edu.umd.cs.findbugs.annotations.NonNull\" />\n          <item index=\"3\" class=\"java.lang.String\" itemvalue=\"android.support.annotation.NonNull\" />\n        </list>\n      </value>\n    </option>\n  </component>\n  <component name=\"ProjectLevelVcsManager\" settingsEditedManually=\"false\">\n    <OptionsSetting value=\"true\" id=\"Add\" />\n    <OptionsSetting value=\"true\" id=\"Remove\" />\n    <OptionsSetting value=\"true\" id=\"Checkout\" />\n    <OptionsSetting value=\"true\" id=\"Update\" />\n    <OptionsSetting value=\"true\" id=\"Status\" />\n    <OptionsSetting value=\"true\" id=\"Edit\" />\n    <ConfirmationsSetting value=\"0\" id=\"Add\" />\n    <ConfirmationsSetting value=\"0\" id=\"Remove\" />\n  </component>\n  <component name=\"ProjectRootManager\" version=\"2\" languageLevel=\"JDK_1_7\" assert-keyword=\"true\" jdk-15=\"true\" project-jdk-name=\"1.8\" project-jdk-type=\"JavaSDK\">\n    <output url=\"file://$PROJECT_DIR$/build/classes\" />\n  </component>\n  <component name=\"ProjectType\">\n    <option name=\"id\" value=\"Android\" />\n  </component>\n  <component name=\"masterDetails\">\n    <states>\n      <state key=\"ProjectJDKs.UI\">\n        <settings>\n          <last-edited>Android API 22 Platform</last-edited>\n          <splitter-proportions>\n            <option name=\"proportions\">\n              <list>\n                <option value=\"0.2\" />\n              </list>\n            </option>\n          </splitter-proportions>\n        </settings>\n      </state>\n    </states>\n  </component>\n</project>"
  },
  {
    "path": ".idea/modules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"ProjectModuleManager\">\n    <modules>\n      <module fileurl=\"file://$PROJECT_DIR$/PasscodeView.iml\" filepath=\"$PROJECT_DIR$/PasscodeView.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/app/app.iml\" filepath=\"$PROJECT_DIR$/app/app.iml\" />\n      <module fileurl=\"file://$PROJECT_DIR$/passcodeview/passcodeview.iml\" filepath=\"$PROJECT_DIR$/passcodeview/passcodeview.iml\" />\n    </modules>\n  </component>\n</project>"
  },
  {
    "path": ".idea/runConfigurations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"RunConfigurationProducerService\">\n    <option name=\"ignoredProducers\">\n      <set>\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer\" />\n        <option value=\"org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer\" />\n      </set>\n    </option>\n  </component>\n</project>"
  },
  {
    "path": ".idea/vcs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project version=\"4\">\n  <component name=\"VcsDirectoryMappings\">\n    <mapping directory=\"$PROJECT_DIR$\" vcs=\"Git\" />\n  </component>\n</project>"
  },
  {
    "path": "README.md",
    "content": "# PasscodeView\n[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)\n[ ![Download](https://api.bintray.com/packages/iammehedi/Maven/online.devliving%3Apasscodeview/images/download.svg) ](https://bintray.com/iammehedi/Maven/online.devliving%3Apasscodeview/_latestVersion)\n\nAn android widget to input passcode.\n\n## Setup\n### Maven\n```xml\n<dependency>\n  <groupId>online.devliving</groupId>\n  <artifactId>passcodeview</artifactId>\n  <version>1.0.3</version>\n  <type>pom</type>\n</dependency>\n```\n### Gradle\n```groovy\ncompile 'online.devliving:passcodeview:1.0.3'\n```\n\n## Usage\n`PasscodeView` is a `ViewGroup` subclass. So it can easily be added in any xml layout file.\n\n```xml\n<online.devliving.passcodeview.PasscodeView\n        android:id=\"@+id/passcode_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        passcodeView:numDigits=\"5\"\n        android:layout_marginTop=\"@dimen/activity_vertical_margin\"\n        />\n```\n\n### Methods\n- `requestToShowKeyboard()` - Request the PasscodeView to be focused programmatically\n- `setText(CharSequence text)` - Set Passcode programmatically\n- `clearText()` - Clear Passcode\n- `getText()` - get entered Passcode\n- `setPasscodeEntryListener(PasscodeEntryListener mPasscodeEntryListener)` - Set a listener to get notified when the Passcode has been entered\n\n### Listener:`PasscodeEntryListener`\n- `onPasscodeEntered(String passcode)` - Called when all the digits of the passcode has been entered\n\n```java\npasscodeView.setPasscodeEntryListener(new PasscodeView.PasscodeEntryListener() {\n            @Override\n            public void onPasscodeEntered(String passcode) {\n                Toast.makeText(SampleActivity.this, \"Passcode entered: \" + passcode, Toast.LENGTH_SHORT).show();\n            }\n        });\n```\n\n### XML Attributes\n- `numDigits` - Number of passcode digits\n- `digitElevation` - Elevation of each digit, only applicable for OS version >= Lollipop\n- `digitRadius` - radius for digit circle `16dip` by default\n- `digitInnerRadius` - radius for digit inner circle `10dip` by default\n- `controlColor` - color of the outer circle in normal state, by default `android:colorControlNormal`\n- `controlColorActivated` - color of outer circle when focused, by default `android:colorControlHighlighted`\n- `digitColorFilled` - fill color of the inner circle, by default `android:colorPrimary`\n- `digitColorBorder` - border color of the inner circle, by default `android:colorPrimaryDark`\n\n## Demo\n![image](demo.gif)\n\n## License\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.3\"\n\n    defaultConfig {\n        applicationId \"com.mhk.android.passcodeviewsample\"\n        minSdkVersion 10\n        targetSdkVersion 25\n        versionCode 2\n        versionName \"1.0.1\"\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:25.3.1'\n    compile project(':passcodeview')\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Volumes/Work/SDK/Android/Development/adt bundle/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/androidTest/java/com/mhk/android/passcodeviewsample/ApplicationTest.java",
    "content": "package com.mhk.android.passcodeviewsample;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.mhk.android.passcodeviewsample\" >\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:theme=\"@style/AppTheme\" >\n\n        <activity android:name=\".SampleActivity\" >\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\"/>\n                <category android:name=\"android.intent.category.LAUNCHER\"/>\n            </intent-filter>\n        </activity>\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/mhk/android/passcodeviewsample/SampleActivity.java",
    "content": "package com.mhk.android.passcodeviewsample;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.util.Log;\nimport android.widget.Toast;\n\nimport online.devliving.passcodeview.PasscodeView;\n\n/**\n * Created by Mehedi Hasan Khan on 9/6/15.\n */\npublic class SampleActivity extends AppCompatActivity{\n\n    @Override\n    public void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.sample_activity);\n\n        final PasscodeView pcView = (PasscodeView) findViewById(R.id.passcode_view);\n\n        pcView.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                pcView.requestToShowKeyboard();\n            }\n        }, 400);\n\n        pcView.setPasscodeEntryListener(new PasscodeView.PasscodeEntryListener() {\n            @Override\n            public void onPasscodeEntered(String passcode) {\n                Toast.makeText(SampleActivity.this, \"Passcode entered: \" + passcode, Toast.LENGTH_SHORT).show();\n            }\n        });\n\n        Log.d(\"SAMPLE\", \"Activity created\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/res/layout/sample_activity.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:passcodeView=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:padding=\"@dimen/activity_vertical_margin\"\n    android:background=\"@android:color/white\">\n\n    <online.devliving.passcodeview.PasscodeView\n        android:id=\"@+id/passcode_view\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        passcodeView:numDigits=\"5\"\n        passcodeView:digitRadius=\"16dp\"\n        passcodeView:digitInnerRadius=\"10dp\"\n        android:layout_marginTop=\"@dimen/activity_vertical_margin\"\n        />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">PasscodeView Sample</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorControlNormal\">#8e8f8f</item>\n        <item name=\"colorControlHighlight\">#c6c7c7</item>\n        <item name=\"colorAccent\">#399ce4</item>\n        <item name=\"colorPrimary\">#2caae1</item>\n        <item name=\"colorPrimaryDark\">#1880ae</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.3.0'\n\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1'\n\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "passcodeview/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "passcodeview/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: \"com.jfrog.bintray\"\n\nversion = \"1.0.3\"\n\nandroid {\n    compileSdkVersion 25\n    buildToolsVersion \"25.0.3\"\n\n    defaultConfig {\n        minSdkVersion 10\n        targetSdkVersion 25\n        versionCode 4\n        versionName version\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:25.3.1'\n}\n\ndef siteUrl = \"https://github.com/iamMehedi/PasscodeView\"\ndef gitUrl = \"https://github.com/iamMehedi/PasscodeView.git\"\n\ngroup = \"online.devliving\"\n\ninstall {\n    repositories.mavenInstaller {\n        // This generates POM.xml with proper parameters\n        pom {\n            project {\n                packaging 'aar'\n\n                // Add your description here\n                name 'online.devliving:passcodeview'\n                description = 'An android widget to input passcode.'\n                url siteUrl\n\n                // Set your license\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n                developers {\n                    developer {\n                        id 'im_mehedi'\n                        name 'Mehedi Hasan Khan'\n                        email 'mehedi.mailing@gmail.com'\n                    }\n                }\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n    failOnError false\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\nartifacts {\n    archives javadocJar\n    archives sourcesJar\n}\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\n\n// https://github.com/bintray/gradle-bintray-plugin\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n\n    configurations = ['archives']\n    pkg {\n        repo = \"Maven\"\n        // it is the name that appears in bintray when logged\n        name = \"online.devliving:passcodeview\"\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n        version {\n            gpg {\n                sign = true //Determines whether to GPG sign the files. The default is false\n                passphrase = properties.getProperty(\"bintray.gpg.password\")\n                //Optional. The passphrase for GPG signing'\n            }\n        }\n    }\n}\n\n//apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'\n"
  },
  {
    "path": "passcodeview/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /Volumes/Work/SDK/Android/Development/adt bundle/sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "passcodeview/src/androidTest/java/online/devliving/passcodeview/ApplicationTest.java",
    "content": "package online.devliving.passcodeview;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "passcodeview/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"online.devliving.passcodeview\">\n\n    <application android:allowBackup=\"true\" >\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "passcodeview/src/main/java/online/devliving/passcodeview/PasscodeView.java",
    "content": "package online.devliving.passcodeview;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.Editable;\nimport android.text.InputFilter;\nimport android.text.InputType;\nimport android.text.TextWatcher;\nimport android.text.method.DigitsKeyListener;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.util.TypedValue;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.inputmethod.EditorInfo;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.EditText;\n\n/**\n * Created by Mehedi Hasan Khan (mehedi.mailing@gmail.com).\n */\npublic class PasscodeView extends ViewGroup{\n\n    EditText mEditText;\n    int mDigitCount;\n\n    private int mDigitWidth;\n    private int mDigitRadius;\n    private int mOuterStrokeWidth;\n    private int mInnerStrokeWidth;\n    private int mDigitInnerRadius;\n    private int mDigitSpacing;\n    private int mDigitElevation;\n\n    private int mControlColor;\n    private int mHighlightedColor;\n    private int mInnerColor;\n    private int mInnerBorderColor;\n\n    private OnFocusChangeListener mOnFocusChangeListener;\n    private PasscodeEntryListener mPasscodeEntryListener;\n\n    public PasscodeView(Context context) {\n        this(context, null);\n    }\n\n    public PasscodeView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public PasscodeView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        // Get style information\n        TypedArray array = getContext().obtainStyledAttributes(attrs, R.styleable.PasscodeView);\n        mDigitCount = array.getInt(R.styleable.PasscodeView_numDigits, 4);\n\n        // Dimensions\n        DisplayMetrics metrics = getResources().getDisplayMetrics();\n        mDigitRadius = array.getDimensionPixelSize(R.styleable.PasscodeView_digitRadius,\n                (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, metrics));\n        mOuterStrokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, metrics);\n        mInnerStrokeWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, metrics);\n        mDigitInnerRadius = array.getDimensionPixelSize(R.styleable.PasscodeView_digitInnerRadius,\n                mDigitRadius - ((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, metrics)));\n\n        if(mDigitInnerRadius > mDigitRadius){\n            mDigitInnerRadius = mDigitRadius - ((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, metrics));\n        }\n\n        mDigitWidth = (mDigitRadius + mOuterStrokeWidth) * 2;\n\n        mDigitSpacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16, metrics);\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            mDigitElevation = array.getDimensionPixelSize(R.styleable.PasscodeView_digitElevation, 0);\n        }\n\n        // Get theme to resolve defaults\n        Resources.Theme theme = getContext().getTheme();\n\n        mControlColor = Color.DKGRAY;\n        // Text colour, default to android:colorControlNormal from theme\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            TypedValue controlColor = new TypedValue();\n            theme.resolveAttribute(android.R.attr.colorControlNormal, controlColor, true);\n            mControlColor = controlColor.resourceId > 0 ? getResources().getColor(controlColor.resourceId) :\n                    controlColor.data;\n        }\n        mControlColor = array.getColor(R.styleable.PasscodeView_controlColor, mControlColor);\n\n        // Accent colour, default to android:colorAccent from theme\n        mHighlightedColor = Color.LTGRAY;\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            TypedValue accentColor = new TypedValue();\n            theme.resolveAttribute(R.attr.colorControlHighlight, accentColor, true);\n            mHighlightedColor = accentColor.resourceId > 0 ? getResources().getColor(accentColor.resourceId) :\n                    accentColor.data;\n        }\n        mHighlightedColor = array.getColor(R.styleable.PasscodeView_controlColorActivated, mHighlightedColor);\n\n        //color for the inner circle\n        mInnerColor = Color.CYAN;\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            TypedValue innerColor = new TypedValue();\n            theme.resolveAttribute(android.R.attr.colorPrimary, innerColor, true);\n            mInnerColor = innerColor.resourceId > 0 ? getResources().getColor(innerColor.resourceId) :\n                    innerColor.data;\n        }\n        mInnerColor = array.getColor(R.styleable.PasscodeView_digitColorFilled, mInnerColor);\n\n        //color for the inner circle border\n        mInnerBorderColor = Color.GREEN;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n            TypedValue innerBorderColor = new TypedValue();\n            theme.resolveAttribute(android.R.attr.colorPrimaryDark, innerBorderColor, true);\n            mInnerBorderColor = innerBorderColor.resourceId > 0 ? getResources().getColor(innerBorderColor.resourceId) :\n                    innerBorderColor.data;\n        }\n        mInnerBorderColor = array.getColor(R.styleable.PasscodeView_digitColorBorder, mInnerBorderColor);\n\n        // Recycle the typed array\n        array.recycle();\n\n        // Add child views\n        setupViews();\n    }\n\n    @Override\n    public boolean shouldDelayChildPressedState() {\n        return false;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        // Measure children\n        for (int i = 0; i < getChildCount(); i ++) {\n            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);\n        }\n\n        // Calculate the size of the view\n        int width = (mDigitWidth * mDigitCount) + (mDigitSpacing * (mDigitCount - 1));\n        setMeasuredDimension(\n                width + getPaddingLeft() + getPaddingRight() + (mDigitElevation * 2),\n                mDigitWidth + getPaddingTop() + getPaddingBottom() + (mDigitElevation * 2));\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        // Position the child views\n        for (int i = 0; i < mDigitCount; i++) {\n            View child = getChildAt(i);\n            int left = i * mDigitWidth + (i > 0 ? i * mDigitSpacing : 0);\n            child.layout(\n                    left + getPaddingLeft() + mDigitElevation,\n                    getPaddingTop() + (mDigitElevation / 2),\n                    left + getPaddingLeft() + mDigitElevation + mDigitWidth,\n                    getPaddingTop() + (mDigitElevation / 2) + mDigitWidth);\n        }\n\n        // Add the edit text as a 1px wide view to allow it to focus\n        getChildAt(mDigitCount).layout(0, 0, 1, getMeasuredHeight());\n    }\n\n    private void setupViews(){\n        setWillNotDraw(false);\n        // Add a digit view for each digit\n        for (int i = 0; i < mDigitCount; i++) {\n            DigitView digitView = new DigitView(getContext(), i);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {\n                digitView.setElevation(mDigitElevation);\n            }\n            addView(digitView);\n        }\n\n        // Add an \"invisible\" edit text to handle input\n        mEditText = new EditText(getContext());\n        mEditText.setBackgroundColor(getResources().getColor(android.R.color.transparent));\n        mEditText.setTextColor(getResources().getColor(android.R.color.transparent));\n        mEditText.setCursorVisible(false);\n        mEditText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(mDigitCount)});\n        mEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n        mEditText.setKeyListener(DigitsKeyListener.getInstance(\"1234567890\"));\n        mEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);\n        mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {\n            @Override\n            public void onFocusChange(View v, boolean hasFocus) {\n                // Update the selected state of the views\n                int length = mEditText.getText().length();\n                updateChilViewSelectionStates(length, hasFocus);\n                // Make sure the cursor is at the end\n                mEditText.setSelection(length);\n\n                // Provide focus change events to any listener\n                if (mOnFocusChangeListener != null) {\n                    mOnFocusChangeListener.onFocusChange(PasscodeView.this, hasFocus);\n                }\n            }\n        });\n\n        mEditText.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n                int length = s.length();\n                updateChilViewSelectionStates(length, mEditText.hasFocus());\n\n                if (length == mDigitCount && mPasscodeEntryListener != null) {\n                    mPasscodeEntryListener.onPasscodeEntered(s.toString());\n                }\n            }\n        });\n        addView(mEditText);\n\n        invalidate();\n    }\n\n    private void updateChilViewSelectionStates(int length, boolean hasFocus){\n        for (int i = 0; i < mDigitCount; i++) {\n            getChildAt(i).setSelected(hasFocus && i == length);\n        }\n    }\n\n    /**\n     * Get the {@link Editable} from the EditText\n     *\n     * @return\n     */\n    public Editable getText() {\n        return mEditText.getText();\n    }\n\n    /**\n     * Set text to the EditText\n     *\n     * @param text\n     */\n    public void setText(CharSequence text) {\n        if (text.length() > mDigitCount) {\n            text = text.subSequence(0, mDigitCount);\n        }\n        mEditText.setText(text);\n        invalidateChildViews();\n    }\n\n    /**\n     * Clear passcode input\n     */\n    public void clearText() {\n        mEditText.setText(\"\");\n        invalidateChildViews();\n    }\n\n    private void invalidateChildViews(){\n        for(int i =0; i<mDigitCount; i++)\n        {\n            getChildAt(i).invalidate();\n        }\n    }\n\n    public void setPasscodeEntryListener(PasscodeEntryListener mPasscodeEntryListener) {\n        this.mPasscodeEntryListener = mPasscodeEntryListener;\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        if (event.getAction() == MotionEvent.ACTION_DOWN) {\n            requestToShowKeyboard();\n            return true;\n        }\n        return super.onTouchEvent(event);\n    }\n\n    /**\n     * Requests the view to be focused and the keyboard to be popped-up\n     */\n    public void requestToShowKeyboard(){\n        // Make sure this view is focused\n        mEditText.requestFocus();\n\n        // Show keyboard\n        InputMethodManager inputMethodManager = (InputMethodManager) getContext()\n                .getSystemService(Context.INPUT_METHOD_SERVICE);\n        inputMethodManager.showSoftInput(mEditText, 0);\n    }\n\n    @Override\n    public OnFocusChangeListener getOnFocusChangeListener() {\n        return mOnFocusChangeListener;\n    }\n\n    @Override\n    public void setOnFocusChangeListener(OnFocusChangeListener l) {\n        mOnFocusChangeListener = l;\n    }\n\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        Parcelable parcelable = super.onSaveInstanceState();\n        SavedState savedState = new SavedState(parcelable);\n        savedState.editTextValue = mEditText.getText().toString();\n        return savedState;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n        SavedState savedState = (SavedState) state;\n        super.onRestoreInstanceState(savedState.getSuperState());\n        mEditText.setText(savedState.editTextValue);\n        mEditText.setSelection(savedState.editTextValue.length());\n    }\n\n    static class SavedState extends BaseSavedState {\n\n        public static final Parcelable.Creator<SavedState> CREATOR =\n                new Parcelable.Creator<SavedState>() {\n                    @Override\n                    public SavedState createFromParcel(Parcel in) {\n                        return new SavedState(in);\n                    }\n\n                    @Override\n                    public SavedState[] newArray(int size) {\n                        return new SavedState[size];\n                    }\n                };\n        String editTextValue;\n\n        public SavedState(Parcelable superState) {\n            super(superState);\n        }\n\n        private SavedState(Parcel source) {\n            super(source);\n            editTextValue = source.readString();\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            super.writeToParcel(dest, flags);\n            dest.writeString(editTextValue);\n        }\n    }\n\n    class DigitView extends View{\n\n        private Paint mOuterPaint, mInnerPaint;\n        private int mPosition = 0;\n\n        public DigitView(Context context, int position)\n        {\n            this(context);\n            mPosition = position;\n        }\n\n        public DigitView(Context context) {\n            this(context, null);\n        }\n\n        public DigitView(Context context, AttributeSet attrs) {\n            this(context, attrs, 0);\n        }\n\n        public DigitView(Context context, AttributeSet attrs, int defStyleAttr) {\n            super(context, attrs, defStyleAttr);\n\n            init();\n        }\n\n        void init(){\n            setWillNotDraw(false);\n            if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){\n                setLayerType(LAYER_TYPE_SOFTWARE, null);\n            }\n            mOuterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n            mOuterPaint.setAlpha(255);\n            mOuterPaint.setDither(true);\n            mOuterPaint.setStyle(Paint.Style.STROKE);\n            mOuterPaint.setStrokeWidth(mOuterStrokeWidth);\n            mOuterPaint.setStrokeCap(Paint.Cap.ROUND);\n            mOuterPaint.setStrokeJoin(Paint.Join.ROUND);\n            mOuterPaint.setShadowLayer(2, 0, 0, Color.parseColor(\"#B4999999\"));\n\n            mInnerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n            mInnerPaint.setAlpha(255);\n            mInnerPaint.setStyle(Paint.Style.FILL_AND_STROKE);\n            mInnerPaint.setStrokeWidth(mInnerStrokeWidth);\n            mInnerPaint.setStrokeCap(Paint.Cap.ROUND);\n            mInnerPaint.setStrokeJoin(Paint.Join.ROUND);\n            mInnerPaint.setColor(mInnerColor);\n\n            invalidate();\n        }\n\n        @Override\n        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n            setMeasuredDimension(mDigitWidth, mDigitWidth);\n        }\n\n        @Override\n        protected void onDraw(Canvas canvas) {\n            float center = getWidth()/2;\n\n            if(isSelected())\n            {\n                mOuterPaint.setColor(mHighlightedColor);\n            }\n            else\n            {\n                mOuterPaint.setColor(mControlColor);\n            }\n            canvas.drawColor(Color.TRANSPARENT);\n            canvas.drawCircle(center, center, mDigitRadius, mOuterPaint);\n            if(mEditText.getText().length() > mPosition)\n            {\n                canvas.drawCircle(center, center, mDigitInnerRadius, mInnerPaint);\n            }\n        }\n    }\n\n    /**\n     * Listener that gets notified when the complete passcode has been entered\n     */\n    public interface PasscodeEntryListener{\n        /**\n         * Called when all the digits of the passcode has been entered\n         * @param passcode - The entered passcode\n         */\n        void onPasscodeEntered(String passcode);\n    }\n}"
  },
  {
    "path": "passcodeview/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"PasscodeView\">\n        <attr name=\"numDigits\" format=\"integer\"/>\n        <attr name=\"digitElevation\" format=\"dimension\"/>\n        <attr name=\"digitRadius\" format=\"dimension\"/>\n        <attr name=\"digitInnerRadius\" format=\"dimension\"/>\n        <attr name=\"controlColor\" format=\"color\"/>\n        <attr name=\"controlColorActivated\" format=\"color\"/>\n        <attr name=\"digitColorFilled\" format=\"color\"/>\n        <attr name=\"digitColorBorder\" format=\"color\"/>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':passcodeview'\n"
  }
]