본문 바로가기
Project/안드로이드 프로젝트(HYPersonnalApp)

[Android Studio/Java] SMS, PhoneState, Contact Read Permission 부여하기(MainActivity)

by 김마리님 2020. 10. 20.

문자를 보내기 위해서는 제일 먼저 필요한 부분은 전화번호입니다.

문자를 보낸 기록도 필요하고, 혹여 상대에게서 문자를 보낸 기록이 없다면 전화번호부도 참조할 수 있어야 합니다.

 

마지막으로, 어머니께서 혹시라도 다른 어머님들께 앱을 배포하실지도 모르니까(그럴 일 없을거 같긴 한데 혹시라도 만약에, 또 휴대폰 변경하시면서 번호가 바뀌실수도 있으니까) 번호를 상수로 기록해두는게 아니라 MainActivity에서 입력받아 SharedPreference에 저장해두도록 합니다.

itstudy-mary.tistory.com/252

 

[Android Studio, Java] (간단하게) SharedPreferenced가 무엇일까?

참고 url : [Android] SharedPreferences 사용하기 [Android] SharedPreferences 사용하기 이래저래 바쁘다는 핑계로 미루다가 오랜만에 포스팅을 하게 되었습니다. 벌써 새해가 밝았네요. 저만 시간이 빨리 가는.

itstudy-mary.tistory.com

모듈화를 위해 SharedPreference나 Permission을 허가받는 것은 죄다 Util로 만들어두었습니다.

 

 

- SharedPreferencedUtil.java

더보기
package com.example.hypersonnalsnsapp.util;

import android.content.Context;
import android.content.SharedPreferences;

public class SharedPreferenceUtil {
    private static final String TAG = "SharedPreferenceUnit";

    public static String SHARED_PREFERENCES_KEY="SharedPreferences_Key";

    public void RegisteredSharedPreference(Context context, String key, String value){
        SharedPreferences sharedPreferences = context.getSharedPreferences(SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor=sharedPreferences.edit();
        editor.putString(key, value);
        DebugLogUtil.logD(TAG, "key : "+key+", value : "+ value);
        editor.commit();

    }

}

 

 

- CheckPermissionUtil.java

 

(이 유틸은 퍼미션을 체크하고, 퍼미션 허가가 없다면 유저에게 퍼미션을 허가받는 코드입니다.)

더보기

로직은 글이 많아 보여도 간단합니다.

1. ContextCompat.checkSelfPermission 으로 현재 앱에 퍼미션이 허가되어있는지 확인합니다.

 

2. 1번의 값은 0과 -1으로 나누어지는데, 각각 Grant와 Denial 입니다. 허가를 받지 못한 경우(Granted와 값이 다를 경우), 이 함수에서는 내장된 교육용 UI 대신 Dialog 박스를 띄웁니다. 퍼미션에 따라 어떤 허가가 필요한지 setMessage로 설명하고, 네, 를 누를 경우 퍼미션을 허가받는 리퀘스트 창을 띄웁니다. 

package com.example.hypersonnalsnsapp.util;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class CheckPermissionUtil {

    private static final String TAG = "CheckPermissionUtil";
    private static final int MY_PERMISSION_REQUEST_READ_SMS = 1001;
    private static boolean result;

    public CheckPermissionUtil() {
        new CheckPermissionUtil();
    }

    public static boolean checkPermission(Activity activity, String requestPermission) {

        String authority = "";

        if(requestPermission.equals(Constant.manifest_permission_Read_SMS)) {
            authority = "문자 목록을";
        }else if(requestPermission.equals(Constant.manifest_permission_Read_Contact)){
            authority = "연락처 목록을";
        }

        result = false;

        int permissionCheck = ContextCompat.checkSelfPermission(activity, requestPermission);

        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {

            Toast.makeText(activity, "권한 승인이 필요합니다.", Toast.LENGTH_SHORT).show();

            if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, requestPermission)) {
                AlertDialog.Builder dialog = new AlertDialog.Builder(activity);
                dialog.setTitle("권한 승인 확인")
                        .setMessage(authority+" 확인하기 위한 권한이 필요합니다. 계속하시겠습니까?")
                        .setPositiveButton("네", (dialog1, which) -> {
                            result = true;
                            activity.requestPermissions(new String[]{requestPermission}, 1001);
                        })
                        .setNegativeButton("아니오", (dialog12, which) ->
                        {
                            Toast.makeText(activity, "권한 승인을 부여받지 못했습니다", Toast.LENGTH_SHORT).show();
                            result = false;
                        }).create().show();
            } else {
                DebugLogUtil.logD(TAG, "아니 잠깐 여기로 오니 너네?");
                activity.requestPermissions(new String[]{requestPermission}, 1001);
            }

        } else {
            result = true;
        }

        DebugLogUtil.logD(TAG, result);
        return result;
    }
}

(코드에서 보이는 모듈화 중 뇌절하는 모습)

 

 

만약 번호를 올바르게 입력하셨고, 권한도 올바르게 부여되어 있으면 다음 액티비티로 넘어가도 되겠죠. 액티비티 유틸도 만듭니다.

 

- ActivityUtil.java

더보기
package com.example.hypersonnalsnsapp.util;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;

import com.example.hypersonnalsnsapp.main.MainActivity;

public class ActivityUtil {

    public ActivityUtil() {
        new ActivityUtil();
    };

    public static void startActivityNoFinish(Activity startActivity, Class<?> activityClass){
        Intent intent= new Intent(startActivity, activityClass);
        startActivity.startActivity(intent);
    }

    public static void startActivityFinish(Activity startActivity, Class<?> activityClass){
        Intent intent= new Intent(startActivity, activityClass);
        startActivity.startActivity(intent);
        startActivity.finish();
    }

}

 

 

이제 필요한 유틸은 없으니 메인 액티비티를 확인합니다.

뷰는 간단합니다. 그저 번호만 입력 받으면 되니까요.

 

- activity_main.xml

더보기

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    tools:context=".main.MainActivity">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/main_guide_explanation"
            android:textColor="@color/color_292929"/>

        <EditText
            android:id="@+id/editTextPhoneNumber"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="phone"
            android:textColor="@color/color_292929"
            android:backgroundTint="@color/color_292929"
            android:singleLine="true"
            />

        <TextView
            android:id="@+id/textViewNextButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/main_button_next"
            android:textColor="@color/striking_red"
            android:layout_marginTop="20dp"
            android:layout_gravity="end"/>

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

 

이제 다음 버튼을 누르면 SharedPrefercenced에 값을 저장해줄겁니다.

이걸 처리해줄 자바 코드를 확인합니다.

 

- MainActivity.java

(제일 핵심이기 때문에 안 접습니당)

 

package com.example.hypersonnalsnsapp.main;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

import android.Manifest;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import com.example.hypersonnalsnsapp.R;
import com.example.hypersonnalsnsapp.selectSMSNumber.SelectSmsActivity;
import com.example.hypersonnalsnsapp.util.ActivityUtil;
import com.example.hypersonnalsnsapp.util.CheckPermissionUtil;
import com.example.hypersonnalsnsapp.util.Constant;
import com.example.hypersonnalsnsapp.util.DebugLogUtil;
import com.example.hypersonnalsnsapp.util.SharedPreferenceUtil;

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    private EditText editTextPhoneNumber;
    private TextView textViewNextButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        findView();
        setListener();
        CheckPermissionUtil.checkPermission(MainActivity.this, Constant.manifest_permission_Read_SMS);
        CheckPermissionUtil.checkPermission(MainActivity.this, Constant.manifest_permission_Read_Contact);
        checkSharedReference();

    }

    private void checkSharedReference() {
        SharedPreferences sharedPreferences = MainActivity.this.getSharedPreferences(SharedPreferenceUtil.SHARED_PREFERENCES_KEY, Activity.MODE_PRIVATE);
        String storedPhoneNumber = sharedPreferences.getString(Constant.sharedPreference_phoneNumber, "");

        if (!storedPhoneNumber.equals("")) {
            ActivityUtil.startActivityFinish(MainActivity.this, SelectSmsActivity.class);
        }
    }

    private void findView() {
        editTextPhoneNumber = findViewById(R.id.editTextPhoneNumber);
        textViewNextButton = findViewById(R.id.textViewNextButton);
    }

    private String getMyPhoneNumber() {
        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_NUMBERS) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
            MainActivity.this.requestPermissions(new String[]{Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.READ_PHONE_STATE},1001);
        }
        String phoneNum = telephonyManager.getLine1Number();
        if(phoneNum.startsWith("+82")){
            phoneNum=phoneNum.replace("+82","0");
        }

        return phoneNum;
    }

    private void setListener() {

        textViewNextButton.setOnClickListener(v -> {

                    hideKeypad();

                    Thread thread = new Thread(() -> {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        String phoneNumber = editTextPhoneNumber.getText().toString();

                        if (phoneNumber.contains("-")) {
                            phoneNumber.replace("-", "");
                        }

                        if (phoneNumber.contains("/")) {
                            phoneNumber.replace("/", "");
                        }

                        if (phoneNumber.contains(" ")) {
                            phoneNumber.replace(" ", "");
                            phoneNumber.trim();
                        }

                        if (phoneNumber.length() < 11) {
                            DebugLogUtil.logD(TAG, "비어있음");
                            Toast.makeText(this, R.string.main_getWrongNumber, Toast.LENGTH_SHORT).show();
                            return;

                        } else if (!phoneNumber.equals(getMyPhoneNumber())) {
                            DebugLogUtil.logD(TAG, getMyPhoneNumber());
                            Toast.makeText(this, R.string.main_getOtherNumber, Toast.LENGTH_SHORT).show();
                            return;
                        } else {
                            getPhoneNumber();
                            checkPermission();
                        }
                    });

                    thread.run();
                }
        );
    }

    private void hideKeypad() {
        InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(editTextPhoneNumber.getWindowToken(), 0);
    }

    private void getPhoneNumber() {
        String phoneNumber = editTextPhoneNumber.getText().toString();

        DebugLogUtil.logD(TAG, phoneNumber);

        SharedPreferenceUtil shUnit = new SharedPreferenceUtil();
        shUnit.RegisteredSharedPreference(this, Constant.sharedPreference_phoneNumber, phoneNumber);


    }

    private void checkPermission() {

        int permissionResultReadSMS = MainActivity.this.checkSelfPermission(Constant.manifest_permission_Read_SMS);
        int permissionResultReadContact = MainActivity.this.checkSelfPermission(Constant.manifest_permission_Read_Contact);
        if (permissionResultReadSMS == PackageManager.PERMISSION_GRANTED && permissionResultReadContact == PackageManager.PERMISSION_GRANTED) {
            ActivityUtil.startActivityNoFinish(MainActivity.this, SelectSmsActivity.class);
        } else {
            if (permissionResultReadSMS == PackageManager.PERMISSION_DENIED) {
                Toast.makeText(this, "권한을 확인해줘야 합니다 ㅠㅜ", Toast.LENGTH_SHORT).show();
                CheckPermissionUtil.checkPermission(MainActivity.this, Constant.manifest_permission_Read_SMS);
            } else if (permissionResultReadContact == PackageManager.PERMISSION_DENIED) {
                Toast.makeText(this, "권한을 확인해줘야 합니다 ㅠㅜ", Toast.LENGTH_SHORT).show();
                CheckPermissionUtil.checkPermission(MainActivity.this, Constant.manifest_permission_Read_Contact);
            }
        }
    }
}

 

먼저 액티비티가 처음 만들어질 때 권한을 확인합니다. 앞서 로직에서도 얘기했지만, 권한이 없다면 따로 안내창을 띄워서 권한 부여를 받을 겁니다. 이후에 여기서 허가 받았는지 한번 더 체크할거구용.

 

뷰는 당연히 이벤트 리스너 걸려면 걸어야 할거고(findView)

 

그리고 현재 앱에 SharedPreferenced로 저장되어있는 휴대폰 번호가 있는지 확인합니다. 만약 있다면 이 액티비티를 거칠 이유가 없으니 바로 넘어가도 되니까요.

 

없다면 번호를 입력하고 다음을 눌러봅니다. 그럼 리스너가 작동합니다.

 

왜 스레드를 썼냐면... hideKeyPad 때문입니다. 바로 사용하니 접히지 않고, 0.1초정도 간격이 있으니까 접히더라고요.

번호를 다양한 형태로 적을 가능성이 있으므로, 다양한 형태를 모두 한 형태(01000000000)로 통일합니다. 통일 후에도 값이 11자리가 아니라면, 번호를 적게 적어서 문자를 보낼 수 없게 되므로 함수를 즉시 종료합니다.

 

혹은 내 번호가 아닌 번호로 보내는 것도 방지하기 위해 내 번호가 아니어도 함수를 즉시 종료합니다. 

 

내 번호를 가져오는 방법은, 위의 getMyPhoneNumber 함수입니다.

저기서 휴대전화 번호를 가져오기 위한 3개의 퍼미션이 부여되지 않았을 경우, MainActivity.this.requestPermissions 함수로 다시 한번 퍼미션 부여를 시도합니다. 퍼미션 부여에 성공했다면 phoneNum에 내 번호를 담고, 만약에 +82 로 번호가 리턴되는 것을 막고자 +82를 우리가 아는 번호로 변경합니다. 그리고 이 값을 리턴합니다.

 

리턴받은 안드로이드 기기의 번호와 입력받은 번호가 같다면 SharedPreferenced 함수로 값을 저장하고, 앞서서 허가받은 퍼미션이 올바르게 작동하는지 알아봅니다. 허가 받았으면 비로소 다음 액티비티로 넘어가고, 허가받지 못했다면 다시 퍼미션 체크를 시도하게 됩니다. 

 

 

 

반응형