Skip to content

Instantly share code, notes, and snippets.

@aucd29
Last active June 1, 2018 06:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aucd29/f10dba3204868989fdfa5a8a7681b5c8 to your computer and use it in GitHub Desktop.
Save aucd29/f10dba3204868989fdfa5a8a7681b5c8 to your computer and use it in GitHub Desktop.
Runtime 퍼미션을 Rx 화 시키기 위해서 끄적거려본 코드 RxPermsisions, Rx 시작을 이제 한달 째라 아직 잘 모르지만 =_ = 암튼 그냥 그냥 만들어 봄
public class PermissionFragment extends Fragment {
private static final Logger mLog = LoggerFactory.getLogger(PermissionFragment.class);
/** 퍼미션 처리에 필요한 파라메터 값 */
protected PermissionParams mParams;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
boolean grantResult = true;
for (int result : grantResults) {
if (result == PackageManager.PERMISSION_DENIED) {
grantResult = false;
break;
}
}
onPermissionResult(grantResult);
}
/**
* 런타임 퍼미션 결과를 처리 한다.
* @param result 처리 결과
*/
protected void onPermissionResult(boolean result) {
if (mLog.isDebugEnabled()) {
mLog.debug("PERMISSION RESULT : " + result);
}
if (result) {
mParams.listener.onResult(mParams.reqCode, true);
} else {
showPermissionDialog();
}
}
/**
* 런타임 퍼미션을 요청 한다.
* @param params 런타임 퍼미션에 필요한 파라메터 정보
*/
public void requestPermissions(@NonNull PermissionParams params) {
mParams = params;
if (mLog.isDebugEnabled()) {
mLog.debug("REQUEST PERMISSION");
}
requestPermissions(params.toArrayPermissions(), params.reqCode);
}
/**
* 퍼미션 결과가 negative 일 경우 팝업창을 띄워 퍼미션을 승낙 하도록 유도 한다.
*/
protected void showPermissionDialog() {
if (mLog.isDebugEnabled()) {
mLog.debug("PARAMS : " + mParams);
}
if (mParams.reqCode == PermissionUtils.REQ_MAIN) {
eventNegative();
return ;
}
IDialogDelegate delegate = PermissionUtils.getDialogDelegate();
String msg = getString(R.string.permission_message);
if (delegate != null) {
delegate.show(IDialogDelegate.CONFIRM, getString(R.string.permission_title), msg, (result, value) -> {
switch (result) {
case OnResultListener.FALSE:
eventNegative();
break;
default:
eventPositive();
break;
}
});
return ;
}
AlertDialog.Builder builder = new AlertDialog.Builder(mParams.activity);
builder.setTitle(R.string.permission_title);
builder.setMessage(msg);
builder.setNegativeButton(string("button_cancel"), (dialog, which) -> {
dialog.dismiss();
eventNegative();
});
builder.setPositiveButton(string("button_set"), (dialog, which) -> {
dialog.dismiss();
eventPositive();
});
builder.setCancelable(false);
builder.show();
}
/**
* showPermissionDialog 에서 negative 버튼을 선택 시 발생 시켜야할 이벤트
*/
protected void eventNegative() {
mParams.listener.onResult(mParams.reqCode, false);
}
/**
* showPermissionDialog 에서 positive 버튼을 선택 시 발생 시켜야할 이벤트
*/
protected void eventPositive() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + mParams.activity.getPackageName()));
startActivityForResult(intent, PermissionUtils.RESULT_ACTION_PERMISSION);
}
/**
* 문자열을 반환 한다.
* @param key 문자열에 해당하는 키 값
* @return 문자열 값
*/
protected String string(@NonNull String key) {
return getString(getResources().getIdentifier(key, "string", getContext().getPackageName()));
}
}
public class PermissionParams {
/** request code */
int reqCode;
/** 타깃이 되는 activity */
FragmentActivity activity;
/** 허용해야할 퍼미션 목록 */
List<String> permissions;
/** 결과를 전달할 리스너 */
OnPermissionListener listener;
private PermissionParams(Builder builder) {
this.reqCode = builder.reqCode;
this.activity = builder.activity;
this.permissions = builder.permissions;
this.listener = builder.listener;
}
public String[] toArrayPermissions() {
return permissions.toArray(new String[permissions.size()]);
}
public int reqCode() {
return reqCode;
}
public FragmentActivity activity() {
return activity;
}
public static Builder builder() {
return new Builder();
}
////////////////////////////////////////////////////////////////////////////////////
//
// Builder
//
////////////////////////////////////////////////////////////////////////////////////
public static class Builder {
private int reqCode = 0;
private FragmentActivity activity;
private List<String> permissions = new ArrayList<>();
private OnPermissionListener listener;
public Builder reqCode(int reqCode) {
this.reqCode = reqCode;
return this;
}
public Builder activity(FragmentActivity activity) {
this.activity = activity;
return this;
}
public Builder activity(Activity activity) {
this.activity = (FragmentActivity) activity;
return this;
}
public Builder permission(@NonNull String permission) {
permissions.add(permission);
return this;
}
public Builder permissions(@NonNull String[] permissions) {
this.permissions.addAll(Arrays.asList(permissions));
return this;
}
public Builder listener(@NonNull OnPermissionListener listener) {
this.listener = listener;
return this;
}
public PermissionParams build() {
return new PermissionParams(this);
}
}
}
public class RxPermissionFragment extends PermissionFragment {
private static final Logger mLog = LoggerFactory.getLogger(RxPermissionFragment.class);
private Observer<? super RxPermissionResult> mObserver;
@Override
protected void onPermissionResult(boolean result) {
if (mLog.isDebugEnabled()) {
mLog.debug("PERMISSION RESULT : " + result);
}
if (result) {
mObserver.onNext(new RxPermissionResult(mParams.reqCode(), true));
} else {
showPermissionDialog();
}
}
public void setObserver(Observer<? super RxPermissionResult> observer) {
mObserver = observer;
}
public void requestPermissions(@NonNull PermissionParams params) {
mParams = params;
if (mLog.isDebugEnabled()) {
mLog.debug("REQUEST PERMISSION");
}
requestPermissions(params.toArrayPermissions(), params.reqCode());
}
@Override
protected void eventNegative() {
mObserver.onNext(new RxPermissionResult(mParams.reqCode(), false));
}
}
public class RxPermissionResult {
public int code;
public boolean result;
public RxPermissionResult(int code, boolean result) {
this.code = code;
this.result = result;
}
}
public final class RxPermissions extends Observable<RxPermissionResult> {
private final PermissionParams mParams;
/**
* 퍼미션을 체크 하기 위해 클래스를 인스턴스 한다.
* @param params 퍼미션 체크에 필요한 파라메터
* @return RxPermissions 객체
*/
public static RxPermissions params(PermissionParams params) {
return new RxPermissions(params);
}
private RxPermissions(PermissionParams params) {
mParams = params;
}
@Override
protected void subscribeActual(Observer<? super RxPermissionResult> observer) {
if (!checkLooperThread(observer)) {
return ;
}
RxPermissionsDisposable disposable = new RxPermissionsDisposable(observer);
observer.onSubscribe(disposable);
if (!PermissionUtils.checkSelfPermission(mParams.activity(), mParams.toArrayPermissions())) {
RxPermissionFragment frgmt = permissionFragment();
frgmt.setObserver(observer);
frgmt.requestPermissions(mParams);
return ;
}
observer.onNext(new RxPermissionResult(mParams.reqCode(), true));
}
private boolean checkLooperThread(final Observer observer) {
if (Looper.myLooper() == null) {
observer.onSubscribe(Disposables.empty());
observer.onError(new IllegalStateException("Calling thread is not associated with Looper"));
return false;
}
return true;
}
private @NonNull RxPermissionFragment permissionFragment() {
FragmentManager manager = mParams.activity().getSupportFragmentManager();
RxPermissionFragment frgmt = (RxPermissionFragment) manager
.findFragmentByTag(RxPermissionFragment.class.getName());
if (frgmt != null) {
return frgmt;
}
frgmt = new RxPermissionFragment();
manager.beginTransaction()
.add(frgmt, RxPermissionFragment.class.getName())
.commitAllowingStateLoss();
manager.executePendingTransactions();
return frgmt;
}
private class RxPermissionsDisposable implements Disposable {
private final AtomicBoolean disposed = new AtomicBoolean(false);
private final Observer<? super RxPermissionResult> observer;
RxPermissionsDisposable(Observer<? super RxPermissionResult> observer) {
this.observer = observer;
}
@Override
public void dispose() {
if (disposed.compareAndSet(false, true)) {
observer.onComplete();
}
}
@Override
public boolean isDisposed() {
return disposed.get();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment