카카오톡 앱을 열때 앱을 잠그는 기능이 있습니다.
앱 열고 닫을때 비밀번호를 요구 하는데요 비슷하게 구현 할 수 있습니다.
0. 앱 작동시
앱 잠금 설정 할때
홈 버튼 누르고 다시 실행시
홈버튼 누르고 다시실행하면
앱 잠금설정 되어 있기 때문에 비밀번호를 요구 합니다.
잠금 비활성화를 누르면 저장되어있던
암호가 삭제 됩니다.
1. 레이아웃
1) 비밀번호 입력 액티비티
비밀번호 입력창 레이아웃 소스 activity_app_lock_password.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/etInputInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="비밀번호 입력"/>
<LinearLayout
android:id="@+id/ll_passcodes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<EditText
android:id="@+id/etPasscode1"
android:gravity="center"
android:maxLength="1"
android:textColor="#000000"
android:textSize="40sp"
android:inputType="textPassword|number"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:singleLine="true">
<requestFocus />
</EditText>
<EditText
android:id="@+id/etPasscode2"
android:gravity="center"
android:maxLength="1"
android:textColor="#000000"
android:textSize="40sp"
android:inputType="textPassword|number"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:singleLine="true">
</EditText>
<EditText
android:id="@+id/etPasscode3"
android:gravity="center"
android:maxLength="1"
android:textColor="#000000"
android:textSize="40sp"
android:inputType="textPassword|number"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:singleLine="true">
</EditText>
<EditText
android:id="@+id/etPasscode4"
android:gravity="center"
android:maxLength="1"
android:textColor="#000000"
android:textSize="40sp"
android:inputType="textPassword|number"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_margin="4dp"
android:layout_weight="1"
android:singleLine="true">
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:layout_marginBottom="16dp"
android:orientation="vertical">
<TableLayout
android:id="@+id/tl_keys"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:gravity="bottom"
android:shrinkColumns="*"
android:stretchColumns="*" >
<TableRow>
<Button
android:id="@+id/btn1"
android:text="1"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btn2"
android:text="2"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btn3"
android:text="3"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
</TableRow>
<TableRow>
<Button
android:id="@+id/btn4"
android:text="4"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btn5"
android:text="5"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btn6"
android:text="6"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
</TableRow>
<TableRow>
<Button
android:id="@+id/btn7"
android:text="7"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btn8"
android:text="8"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btn9"
android:text="9"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
</TableRow>
<TableRow>
<Button
android:id="@+id/btnClear"
android:clickable="false"
android:focusable="false"
android:focusableInTouchMode="false"
android:text="CLEAR" />
<Button
android:id="@+id/btn0"
android:text="0"
android:textSize="18dp"
android:gravity="center"
android:layout_margin="5dp"
android:layout_width="120dp"
android:layout_height="48dp"/>
<Button
android:id="@+id/btnErase"
android:text="DEL" />
</TableRow>
</TableLayout>
</LinearLayout>
</LinearLayout>
2) 앱 잠금 테스트 액티비티
비밀번호 잠금 삭제 또는 변경 테스트 할 수 있는 메인 액티비티 레이아웃
activity_app_lock.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btnSetLock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="잠금 설정"/>
<Button
android:id="@+id/btnSetDelLock"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="잠금 비활성화"/>
<Button
android:id="@+id/btnChangePwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="암호 변경"/>
</LinearLayout>
2. 코틀린 소스
AppLockConst.kt
MainActivity에서 intent로 AppPassWordActivity로 날려 Type 보낼때 사용
object AppLockConst {
val type = "type"
val ENABLE_PASSLOCK = 1 // 잠금설정
val DISABLE_PASSLOCK = 2 // 잠금 비활성화
val CHANGE_PASSWORD = 3 // 암호변경
val UNLOCK_PASSWORD = 4 // 잠금해제
}
AppLock.kt
앱 잠금 비밀번호를 SharedPreference에 저장, 삭제, 잠금여부, 비밀번호가 맞는지 확인
class AppLock(context: Context) {
private var sharedPref = context.getSharedPreferences("appLock", Context.MODE_PRIVATE)
// 잠금 설정
fun setPassLock(password : String){
sharedPref.edit().apply{
putString("applock", password)
apply()
}
}
// 잠금 설정 제거
fun removePassLock(){
sharedPref.edit().apply{
remove("applock")
apply()
}
}
// 입력한 비밀번호가 맞는가?
fun checkPassLock(password: String): Boolean {
return sharedPref.getString("applock","0") == password
}
// 잠금 설정이 되어있는가?
fun isPassLockSet(): Boolean {
if(sharedPref.contains("applock")){
return true
}
return false
}
}
AppPassWordActivity.kt
비밀번호 입력창 Activity 제어
activity_app_lock_password 레이아웃 제어
class AppPassWordActivity : AppCompatActivity(){
private var oldPwd =""
private var changePwdUnlock = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_app_lock_password)
val buttonArray = arrayListOf<Button>(btn0, btn1, btn2, btn3, btn4, btn5, btn6, btn7 ,btn8, btn9, btnClear, btnErase)
for (button in buttonArray){
button.setOnClickListener(btnListener)
}
}
// 버튼 클릭 했을때
private val btnListener = View.OnClickListener { view ->
var currentValue = -1
when(view.id){
R.id.btn0 -> currentValue = 0
R.id.btn1 -> currentValue = 1
R.id.btn2 -> currentValue = 2
R.id.btn3 -> currentValue = 3
R.id.btn4 -> currentValue = 4
R.id.btn5 -> currentValue = 5
R.id.btn6 -> currentValue = 6
R.id.btn7 -> currentValue = 7
R.id.btn8 -> currentValue = 8
R.id.btn9 -> currentValue = 9
R.id.btnClear -> onClear()
R.id.btnErase -> onDeleteKey()
}
val strCurrentValue = currentValue.toString() // 현재 입력된 번호 String으로 변경
if (currentValue != -1){
when {
etPasscode1.isFocused -> {
setEditText(etPasscode1, etPasscode2, strCurrentValue)
}
etPasscode2.isFocused -> {
setEditText(etPasscode2, etPasscode3, strCurrentValue)
}
etPasscode3.isFocused -> {
setEditText(etPasscode3, etPasscode4, strCurrentValue)
}
etPasscode4.isFocused -> {
etPasscode4.setText(strCurrentValue)
}
}
}
// 비밀번호를 4자리 모두 입력시
if (etPasscode4.text.isNotEmpty() && etPasscode3.text.isNotEmpty() && etPasscode2.text.isNotEmpty() && etPasscode1.text.isNotEmpty()) {
inputType(intent.getIntExtra("type", 0))
}
}
// 한 칸 지우기를 눌렀을때
private fun onDeleteKey() {
when {
etPasscode1.isFocused -> {
etPasscode1.setText("")
}
etPasscode2.isFocused -> {
etPasscode1.setText("")
etPasscode1.requestFocus()
}
etPasscode3.isFocused -> {
etPasscode2.setText("")
etPasscode2.requestFocus()
}
etPasscode4.isFocused -> {
etPasscode3.setText("")
etPasscode3.requestFocus()
}
}
}
// 모두 지우기
private fun onClear(){
etPasscode1.setText("")
etPasscode2.setText("")
etPasscode3.setText("")
etPasscode4.setText("")
etPasscode1.requestFocus()
}
// 입력된 비밀번호를 합치기
private fun inputedPassword():String {
return "${etPasscode1.text}${etPasscode2.text}${etPasscode3.text}${etPasscode4.text}"
}
// EditText 설정
private fun setEditText(currentEditText : EditText, nextEditText: EditText, strCurrentValue : String){
currentEditText.setText(strCurrentValue)
nextEditText.requestFocus()
nextEditText.setText("")
}
// Intent Type 분류
private fun inputType(type : Int){
when(type){
AppLockConst.ENABLE_PASSLOCK ->{ // 잠금설정
if(oldPwd.isEmpty()){
oldPwd = inputedPassword()
onClear()
etInputInfo.text = "다시 한번 입력"
}
else{
if(oldPwd == inputedPassword()){
AppLock(this).setPassLock(inputedPassword())
setResult(Activity.RESULT_OK)
finish()
}
else{
onClear()
oldPwd = ""
etInputInfo.text = "비밀번호 입력"
}
}
}
AppLockConst.DISABLE_PASSLOCK ->{ // 잠금삭제
if(AppLock(this).isPassLockSet()){
if(AppLock(this).checkPassLock(inputedPassword())) {
AppLock(this).removePassLock()
setResult(Activity.RESULT_OK)
finish()
}
else {
etInputInfo.text = "비밀번호가 틀립니다."
onClear()
}
}
else{
setResult(Activity.RESULT_CANCELED)
finish()
}
}
AppLockConst.UNLOCK_PASSWORD ->
if(AppLock(this).checkPassLock(inputedPassword())) {
setResult(Activity.RESULT_OK)
finish()
}else{
etInputInfo.text = "비밀번호가 틀립니다."
onClear()
}
AppLockConst.CHANGE_PASSWORD -> { // 비밀번호 변경
if (AppLock(this).checkPassLock(inputedPassword()) && !changePwdUnlock) {
onClear()
changePwdUnlock = true
etInputInfo.text = "새로운 비밀번호 입력"
}
else if (changePwdUnlock) {
if (oldPwd.isEmpty()) {
oldPwd = inputedPassword()
onClear()
etInputInfo.text = "새로운 비밀번호 다시 입력"
} else {
if (oldPwd == inputedPassword()) {
AppLock(this).setPassLock(inputedPassword())
setResult(Activity.RESULT_OK)
finish()
} else {
onClear()
oldPwd = ""
etInputInfo.text = "현재 비밀번호 다시 입력"
changePwdUnlock = false
}
}
} else {
etInputInfo.text = "비밀번호가 틀립니다."
changePwdUnlock = false
onClear()
}
}
}
}
}
MainActivity.kt
잠금 설정, 잠금 비활성화, 암호 변경 버튼을 눌렀을때
Intent를 AppPassWordActivity로 startActivityForResult를 사용하여 보낸다.
class MainActivity : AppCompatActivity() {
var lock = true // 잠금 상태 여부 확인
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_app_lock)
init()
// 잠금 설정 버튼을 눌렀을때
btnSetLock.setOnClickListener {
val intent = Intent(this, AppPassWordActivity::class.java).apply {
putExtra(AppLockConst.type, AppLockConst.ENABLE_PASSLOCK)
}
startActivityForResult(intent, AppLockConst.ENABLE_PASSLOCK)
}
// 잠금 비활성화 버튼을 눌렀을때
btnSetDelLock.setOnClickListener{
val intent = Intent(this, AppPassWordActivity::class.java).apply {
putExtra(AppLockConst.type, AppLockConst.DISABLE_PASSLOCK)
}
startActivityForResult(intent, AppLockConst.DISABLE_PASSLOCK)
}
// 암호 변경버튼을 눌렀을때
btnChangePwd.setOnClickListener {
val intent = Intent(this, AppPassWordActivity::class.java).apply {
putExtra(AppLockConst.type, AppLockConst.CHANGE_PASSWORD)
}
startActivityForResult(intent, AppLockConst.CHANGE_PASSWORD)
}
}
// startActivityForResult 결과값을 받는다.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode){
AppLockConst.ENABLE_PASSLOCK ->
if(resultCode == Activity.RESULT_OK){
Toast.makeText(this, "암호 설정 됨", Toast.LENGTH_SHORT).show()
init()
lock = false
}
AppLockConst.DISABLE_PASSLOCK ->
if(resultCode == Activity.RESULT_OK){
Toast.makeText(this, "암호 삭제 됨", Toast.LENGTH_SHORT).show()
init()
}
AppLockConst.CHANGE_PASSWORD ->
if(resultCode == Activity.RESULT_OK){
Toast.makeText(this, "암호 변경 됨", Toast.LENGTH_SHORT).show()
lock = false
}
AppLockConst.UNLOCK_PASSWORD ->
if(resultCode == Activity.RESULT_OK){
Toast.makeText(this, "잠금 해제 됨", Toast.LENGTH_SHORT).show()
lock = false
}
}
}
// 액티비티가 onStart인 경우
override fun onStart() {
super.onStart()
if(lock && AppLock(this).isPassLockSet()){
val intent = Intent(this, AppPassWordActivity::class.java).apply {
putExtra(AppLockConst.type, AppLockConst.UNLOCK_PASSWORD)
}
startActivityForResult(intent, AppLockConst.UNLOCK_PASSWORD)
}
}
// 액티비티가 onPause인경우
override fun onPause() {
super.onPause()
if (AppLock(this).isPassLockSet()) {
lock = true // 잠금로 변경
}
}
// 버튼 비활성화
private fun init(){
if (AppLock(this).isPassLockSet()){
btnSetLock.isEnabled = false
btnSetDelLock.isEnabled = true
btnChangePwd.isEnabled = true
lock = true
}
else{
btnSetLock.isEnabled = true
btnSetDelLock.isEnabled = false
btnChangePwd.isEnabled = false
lock = false
}
}
}
3. 앱 작동 순서
1) 메인 액티비티에서 암호 설정 버튼을 누릅니다.
2) 메인 액티비티에서 Intent를 보냅니다.
val intent = Intent(this, AppPassWordActivity::class.java).apply {
putExtra(AppLockConst.type, AppLockConst.ENABLE_PASSLOCK)
}
startActivityForResult(intent, AppLockConst.ENABLE_PASSLOCK)
3) AppPassWordActivity 에서 비밀번호 4자리 모두 입력시 inputType() 함수가 실행 됩니다.
잠금이 설정이 된경우 Activity.RESULT_OK를 결과 값을 메인 액티비티로 전송합니다.
private fun inputType(type : Int){
when(type){
AppLockConst.ENABLE_PASSLOCK ->{ // 잠금설정
if(oldPwd.isEmpty()){
oldPwd = inputedPassword()
onClear()
etInputInfo.text = "다시 한번 입력"
}
else{
if(oldPwd == inputedPassword()){
AppLock(this).setPassLock(inputedPassword())
setResult(Activity.RESULT_OK) // 결과 전송
finish()
}
else{
onClear()
oldPwd = ""
etInputInfo.text = "비밀번호 입력"
}
}
}
...
4) 메인 액티비티에서 결과 값을 수신하여 requestCode가 ENABLE_PASSLOCK 인 경우 토스트를 호출 합니다.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode){
AppLockConst.ENABLE_PASSLOCK ->
if(resultCode == Activity.RESULT_OK){
Toast.makeText(this, "암호 설정 됨", Toast.LENGTH_SHORT).show()
init()
lock = false
}
...
'프로그래밍' 카테고리의 다른 글
[Kotlin]코틀린 해당 월의 일(day)갯수 계산 (0) | 2021.01.15 |
---|---|
[Kotlin] 두 날짜간 차이 구하기 timeInMillis (0) | 2020.08.21 |
[Kotlin] 안드로이드 알람 매니저 알람설정 (0) | 2020.03.27 |
파이썬 turtle로 태극기 태극 문양 그리기 (0) | 2019.04.08 |