Before 2022/Android

퍼미션 체크(권한 허용 요청) 커스텀 리스트 뷰 리팩토링

Eljoe 2019. 3. 15. 16:01

기존에 작성한 퍼미션 체크 커스텀 리스트 뷰(링크)가 자잘한 오류가 발생했고 또한 상세한 설명이 붙여지지 않았다.


아래에 새로 리팩토링한 코드로 다시 쓴다.(기존 XML은 동일함)


* RecyclerView로 적용하고자 하는 사람을 위해 기존 소스에 ViewHolder 패턴을 추가하였다.


1. Adapter

public class PermissionAdapter extends BaseAdapter {
    private ArrayList<Permission> permissionItems = new ArrayList<>();

    public PermissionAdapter(Context context) {
        for (PermissionType permissionType : PermissionType.values()) {
            Permission permission = new Permission();

            switch (permissionType.getPermissionValue()) {
                case Manifest.permission.READ_PHONE_STATE:
                    permission.setIcon(context.getResources().getDrawable(R.drawable.baseline_call_white_18));
                    permission.setName("전화");
                    permission.setContent("출, 퇴근 기록 시 전화번호를 저장하기 위해 해당 권한이 필요합니다.");
                    break;
                case Manifest.permission.WRITE_EXTERNAL_STORAGE:
                    permission.setIcon(context.getResources().getDrawable(R.drawable.baseline_storage_white_18));
                    permission.setName("저장소");
                    permission.setContent("프로필 사진을 등록하기 위해 해당 권한이 필요합니다.");
                    break;
                case Manifest.permission.RECORD_AUDIO:
                    permission.setIcon(context.getResources().getDrawable(R.drawable.baseline_record_voice_over_white_18));
                    permission.setName("녹음");
                    permission.setContent("인증 등록 데이터 송신을 위해 해당 권한이 필요합니다.");
                    break;
            }
            permissionItems.add(permission);
        }
    }

    @Override
    public int getCount() {
        return permissionItems.size();
    }

    @Override
    public Permission getItem(int position) {
        return permissionItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        Context context = parent.getContext();

        if (convertView != null) {
            holder = (ViewHolder) convertView.getTag();
        } else {
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.list_view_permission, parent, false);
            holder = new ViewHolder(convertView);
            convertView.setTag(holder);
        }

        String permissionValue = PermissionType.values()[position].getPermissionValue();

        // 퍼미션 체크에 따른 이벤트 리스너
        PermissionListener permissionListener = new PermissionListener() {
            @Override
            public void onPermissionGranted() {
                // 해당 퍼미션 권한이 허용된 경우

                // 허용된 경우 체크박스 체크 및 클릭 잠금
                holder.mCbPermissionCheck.setChecked(true);
                holder.mCbPermissionCheck.setClickable(false);

                //허용된 경우 퍼미션 영역 클릭 잠금
                holder.mClWrap.setClickable(false);

                // 퍼미션이 전부 허용된 경우
                if (permissionCheck(context)) {
                    // 화면 전환
                    Intent intent = new Intent(context, MainActivity.class);
                    context.startActivity(intent);
                    ((Activity) context).finish();
                }
            }

            @Override
            public void onPermissionDenied(List<String> deniedPermissions) {
                // 퍼미션 권한이 허용되지 않은 경우

                // 체크 해제
                holder.mCbPermissionCheck.setChecked(false);
            }
        };

        // 퍼미션 권한이 허용되지 않은 경우
        if (!PermissionType.values()[position].permissionCheck(context)) {
            // 체크박스 체크 해제
            holder.mCbPermissionCheck.setChecked(false);

            // 해당 체크박스를 클릭한 경우 퍼미션 다이얼로그 호출
            holder.mCbPermissionCheck.setOnClickListener(v -> showPermission(context, permissionListener, permissionValue));

            // 해당 퍼미션 영역을 클릭한 경우 퍼미션 다이얼로그 호출
            holder.mClWrap.setOnClickListener(v -> showPermission(context, permissionListener, permissionValue));
        } else {
            // 허용된 경우 체크박스 체크 및 클릭 잠금
            holder.mCbPermissionCheck.setChecked(true);
            holder.mCbPermissionCheck.setClickable(false);
            //허용된 경우 퍼미션 영역 클릭 잠금
            holder.mClWrap.setClickable(false);
        }

        Permission permission = permissionItems.get(position);

        Glide.with(context)
                .load(permission.getIcon())
                .into(holder.mIvPermission);

        holder.mTvPermissionName.setText(permission.getName());

        holder.mTvPermissionContent.setText(permission.getContent());

        return convertView;
    }

    static class ViewHolder {
        @BindView(R.id.cl_wrap)
        ConstraintLayout mClWrap;
        @BindView(R.id.iv_permission)
        ImageView mIvPermission;
        @BindView(R.id.tv_permission_name)
        TextView mTvPermissionName;
        @BindView(R.id.tv_permission_content)
        TextView mTvPermissionContent;
        @BindView(R.id.cb_permission_check)
        CheckBox mCbPermissionCheck;

        ViewHolder(View view) {
            ButterKnife.bind(this, view);
        }
    }

    private void showPermission(Context context, PermissionListener permissionListener, String permission) {
        TedPermission.with(context)
                .setPermissionListener(permissionListener)
                .setDeniedMessage("모든 권한이 승인되지 않은 경우, 근태관리 앱을 사용할 수 없습니다.")
                .setPermissions(permission)
                .check();
    }

    private boolean permissionCheck(Context context) {
        for (PermissionType permissionType : PermissionType.values()) {
            if (!permissionType.permissionCheck(context)) {
                return false;
            }
        }
        return true;
    }
}
2. Model
// 코틀린 data class로 기존 모델 대체
data class Permission(
        var icon: Drawable? = null,
        var name: String = "",
        var content: String = ""
)

3. Enum(Permission 열거형)

// 재사용을 위해 코틀린 열거형으로 퍼미션 상수 및 퍼미션 체크 함수 작성
enum class PermissionType(val permissionValue: String) {
    READ_PHONE_STATE(Manifest.permission.READ_PHONE_STATE), // 전화
    WRITE_EXTERNAL_STORAGE(Manifest.permission.WRITE_EXTERNAL_STORAGE), // 저장소
    RECORD_AUDIO(Manifest.permission.RECORD_AUDIO); // 녹음

    // 퍼미션 체크
    fun permissionCheck(context: Context) = 
            ContextCompat.checkSelfPermission(context, permissionValue) == PackageManager.PERMISSION_GRANTED
}

4. Activity

public class PermissionActivity extends Activity {
    @BindView(R.id.lv_permission)
    ListView mLvPermission;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_permission);
        ButterKnife.bind(this);

        PermissionAdapter permissionAdapter = new PermissionAdapter(this);
        mLvPermission.setAdapter(permissionAdapter);
    }
}


'Before 2022 > Android' 카테고리의 다른 글

Event Bus  (0) 2019.05.20
FCM 푸시 구현하기 - 준비 작업  (0) 2019.04.09
퍼미션 Enum으로 관리하기  (0) 2019.03.13
안드로이드 사운드 기기 및 상태 관리(Kotlin)  (0) 2019.03.13
안드로이드 고음질 녹음  (0) 2019.01.31