Lollipin is a Lollipop material design-styled android Pincode library that provides developers to implement a material Pincode activity without any hustle. Now, the question is Why one will use the Lollipin library.
- Password protection: The password itself is not saved, only it’s hash using the SHA-1 algorithm. This hash is then saved in the SharedPreferences, allowing to verify that the user entered the right PinCode, without giving the possibility to retrieve it.
- Introducing Fingerprint: Once the user has enabled the password, he can also use his fingerprint scanner to unlock his device.
- Developer friendly: This awesome library gives you a stunning prebuild User interface with various methods to ease the work.
A sample video is given below to get an idea about what we are going to do in this article. Note that we are going to implement this project using the Kotlin language.
Step by Step Implementation
Step 1: Create a New Project
To create a new project in Android Studio please refer to How to Create/Start a New Project in Android Studio. Note that select Kotlin as the programming language.
Step 2: Add dependency
Add these following dependencies into your project, which will import the Lollipin library into your existing project.
// Paste this in build.gradle app level // This will import the Lollipin library into your existing project implementation ('com.github.omadahealth:lollipin:2.1.0@aar'{ transitive = true } // Paste this in your build.gradle project level // This is for custom ripple animation allprojects { repositories { maven{ url "https://github.com/omadahealth/omada-nexus/raw/master/release" } jcenter() } }
Step 3:
So, let’s discuss the core components of the Lollipin library. So basically, we need to create a dedicated activity for implementing our locker activity. In our case, we made a PinCodeKotlin activity for this purpose.
PinCodeKotlin Activity
import android.widget.Toast
import com.github.omadahealth.lollipin.lib.managers.AppLockActivity
// Here we are extending our activity with // AppLockActivity so that we can use // its core features class PinCodeKotlin : AppLockActivity() {
// For Implementing forgot pin logic
override fun showForgotDialog() {
Toast.makeText( this , "Implement your forgot password logic here." ,Toast.LENGTH_LONG).show()
}
// For handling pin failure events
override fun onPinFailure(attempts: Int) {
Toast.makeText( this , "Pin entered is Incorrect and attempts done are $attempts" ,Toast.LENGTH_LONG).show()
}
// For handling pin success events
override fun onPinSuccess(attempts: Int) {
Toast.makeText( this , "Correct Pin" ,Toast.LENGTH_LONG).show()
}
// For overriding default length option
// We can override the size of
// Pin required as we want
override fun getPinLength(): Int {
return 4
}
} |
After this step, we need to tell the Lollipin library to use this library. So we can do this in two ways.
- By telling the library in each activity
- By telling the library in one application-level class
We are going to use the 2nd method as it is mostly suggested by the library itself.
App class
We also need to attach this class to our Android manifest file using the name attribute. Our AndroidManifest.xml is below
<? xml version = "1.0" encoding = "utf-8" ?>
package = "in.kay.gfglollipinapp" >
< application
android:allowBackup = "true"
android:icon = "@mipmap/ic_launcher"
android:name = ".app"
android:label = "@string/app_name"
android:roundIcon = "@mipmap/ic_launcher_round"
android:supportsRtl = "true"
android:theme = "@style/Theme.GFGLollipinApp" >
< activity
android:name = ".LockedActivity"
android:exported = "false" />
< activity
android:name = ".PinCodeKotlin"
android:exported = "false" />
< activity
android:name = ".MainActivity"
android:exported = "true" >
< intent-filter >
< action android:name = "android.intent.action.MAIN" />
< category android:name = "android.intent.category.LAUNCHER" />
</ intent-filter >
</ activity >
</ application >
</ manifest >
|
import android.app.Application
import com.github.omadahealth.lollipin.lib.managers.LockManager
class app: Application() {
override fun onCreate() {
super .onCreate()
// Here we are enabling our
// custom Pin code activity
LockManager.getInstance().enableAppLock( this ,PinCodeKotlin:: class .java)
// We are setting custom logo
// for our Pin code activity
LockManager.getInstance().appLock.logoId=R.drawable.ic_gfg
// This is used to give locker a custom timeout setting
// It is in milliseconds
// LockManager.getInstance().appLock.timeout=4000
}
} |
MainActivity
Now, we need to call the different core functions of the library from our main Activity.
import `in`.kay.gfglollipinapp.databinding.ActivityMainBinding
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.github.omadahealth.lollipin.lib.managers.AppLock
import com.github.omadahealth.lollipin.lib.managers.LockManager
class MainActivity : AppCompatActivity() {
// This is view binding which is used to
// bind view without those long findViewbyIds line
private lateinit var binding: ActivityMainBinding
// We are creating a global locker instance for our work
private var locker = LockManager.getInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
// locker.appLock.logoId=R.drawable.ic_gfg
// Used to enable our locker first time
binding.btnEnable.setOnClickListener {
// We are fwding app to PinCodeKotlin
// class for enabling the PinCode
val intent = Intent( this @MainActivity , PinCodeKotlin:: class .java)
// We add some extras which is provided by library
intent.putExtra(AppLock.EXTRA_TYPE, AppLock.ENABLE_PINLOCK)
startActivityForResult(intent, 101 )
}
binding.btnChangePin.setOnClickListener {
val intent = Intent( this @MainActivity , PinCodeKotlin:: class .java)
// We are checking that is our passcode is already set or not
// In simple terms if user is new and he didn't set the passcode
// then we will send it to choose new passcode
if (locker.isAppLockEnabled && locker.appLock.isPasscodeSet) {
intent.putExtra(AppLock.EXTRA_TYPE, AppLock.CHANGE_PIN)
startActivity(intent)
} else {
intent.putExtra(AppLock.EXTRA_TYPE, AppLock.ENABLE_PINLOCK)
startActivityForResult(intent, 101 )
}
}
binding.btnGoToLocked.setOnClickListener {
// This is simple intent for LockedActivity
val intent = Intent( this @MainActivity , LockedActivity:: class .java)
startActivity(intent)
}
// This is to disable the PinCode
binding.btnDisable.setOnClickListener {
locker.disableAppLock()
Toast.makeText( this , "Disabled pin code successfully" ,Toast.LENGTH_LONG).show()
}
}
// This is used to get some external calls to our activity
// as we are passing some result code for some operations
// which will send the result and the data by this method
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super .onActivityResult(requestCode, resultCode, data)
when (requestCode) {
101 -> {
Toast.makeText( this , "PinCode enabled" , Toast.LENGTH_SHORT).show()
}
}
}
} |
So let’s design our layout file for this purpose
activity_main.xml
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:background = "@color/white"
tools:context = ".MainActivity" >
<!-- This is tool bar use to add some
header functionality to our app-->
< Toolbar
android:id = "@+id/toolbar"
android:layout_width = "match_parent"
android:layout_height = "56dp"
android:background = "@color/gfg"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" >
<!--This is the header textview-->
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_gravity = "center"
android:fontFamily = "@font/font_gilroy_bold"
android:text = "@string/str_gfg"
android:textColor = "@color/white"
android:textSize = "24sp" />
</ Toolbar >
<!-- This is button used to add
some interaction work-->
< Button
android:id = "@+id/btn_enable"
android:layout_width = "match_parent"
android:layout_height = "56dp"
android:layout_marginStart = "24dp"
android:layout_marginTop = "80dp"
android:layout_marginEnd = "24dp"
android:background = "@drawable/ic_btn"
android:fontFamily = "@font/font_gilroy_medium"
android:text = "@string/str_enable_pincode"
android:textAllCaps = "false"
android:textColor = "@color/gfg"
android:textSize = "16sp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/toolbar"
app:layout_constraintVertical_bias = "0.0" />
< Button
android:id = "@+id/btn_change_pin"
android:layout_width = "match_parent"
android:layout_height = "56dp"
android:layout_marginStart = "24dp"
android:layout_marginTop = "80dp"
android:layout_marginEnd = "24dp"
android:background = "@drawable/ic_btn"
android:fontFamily = "@font/font_gilroy_medium"
android:text = "@string/str_set_pin"
android:textAllCaps = "false"
android:textColor = "@color/gfg"
android:textSize = "16sp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "@+id/btn_enable"
app:layout_constraintVertical_bias = "0.0" />
< Button
android:id = "@+id/btn_disable"
android:layout_width = "match_parent"
android:layout_height = "56dp"
android:layout_marginStart = "24dp"
android:layout_marginTop = "80dp"
android:layout_marginEnd = "24dp"
android:background = "@drawable/ic_btn"
android:fontFamily = "@font/font_gilroy_medium"
android:text = "@string/str_disable"
android:textAllCaps = "false"
android:textColor = "@color/gfg"
android:textSize = "16sp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "@+id/btn_change_pin"
app:layout_constraintVertical_bias = "0.0" />
< Button
android:id = "@+id/btn_go_to_locked"
android:layout_width = "match_parent"
android:layout_height = "56dp"
android:layout_marginStart = "24dp"
android:layout_marginEnd = "24dp"
android:background = "@drawable/ic_btn"
android:fontFamily = "@font/font_gilroy_medium"
android:text = "@string/str_locked"
android:textAllCaps = "false"
android:textColor = "@color/gfg"
android:layout_marginTop = "80dp"
android:textSize = "16sp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintHorizontal_bias = "0.0"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "@+id/btn_disable"
app:layout_constraintVertical_bias = "0.0" />
< ImageView
android:id = "@+id/imageView"
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:layout_marginBottom = "32dp"
android:src = "@drawable/ic_gfg"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toBottomOf = "@+id/btn_disable"
app:layout_constraintVertical_bias = "1.0" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
and lastly, we will design our locked activity which will be locked after the X seconds which is the timeout time.
LockedActivity
import `in`.kay.gfglollipinapp.databinding.ActivityLockedBinding
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.github.omadahealth.lollipin.lib.PinActivity
import com.github.omadahealth.lollipin.lib.PinCompatActivity
class LockedActivity : PinCompatActivity() {
private lateinit var binding: ActivityLockedBinding
override fun onCreate(savedInstanceState: Bundle?) {
super .onCreate(savedInstanceState)
binding= ActivityLockedBinding.inflate(layoutInflater)
setContentView(binding.root)
}
} |
and the layout for this activity
ActivityLocked.xml
<? xml version = "1.0" encoding = "utf-8" ?>
< androidx.constraintlayout.widget.ConstraintLayout android:layout_width = "match_parent"
android:background = "@color/white"
android:layout_height = "match_parent"
tools:context = ".LockedActivity" >
< TextView
android:layout_width = "wrap_content"
android:layout_height = "wrap_content"
android:fontFamily = "@font/font_gilroy_bold"
android:text = "Unlocked Activity"
android:textColor = "@color/gfg"
android:textSize = "32sp"
app:layout_constraintBottom_toBottomOf = "parent"
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
app:layout_constraintTop_toTopOf = "parent" />
</ androidx.constraintlayout.widget.ConstraintLayout >
|
So, here we are ready to go. Run the app now.