Подтвердить что ты не робот

OnRequestPermissionsResult не вызывается в фрагменте диалога

Я начал работать над разрешением на запуск Android M. Здесь я столкнулся с проблемой, что если requestPermissions вызывается из класса Dialog Fragment, тогда onRequestPermissionsResult не получает вызов в том же классе Dialog Fragment. Но если requestPermissions вызывается из класса Activity class или Fragment, тогда метод onRequestPermissionsResult вызывается в том же классе.

Вот мой пример кода:

public class ContactPickerDialog extends DialogFragment {
    private static final int READ_CONTACTS_REQUEST_CODE = 12;
    private Context mContext;

    private void loadContact() {
        if(hasPermission(mContext, Manifest.permission.READ_CONTACTS)){
            new ContactSyncTask().execute();
        } else {
            this.requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, READ_CONTACTS_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        Logger.d("TAG", "dialog onRequestPermissionsResult");
        switch (requestCode) {
            case READ_CONTACTS_REQUEST_CODE:
                // Check Permissions Granted or not
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    new ContactSyncTask().execute();
                } else {
                    // Permission Denied
                    Toast.makeText(getActivity(), "Read contact permission is denied", Toast.LENGTH_SHORT).show();
                }
            break;
            default:
                super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

    private static boolean hasPermission(Context context, String permission){
        return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
    }

} 

Здесь в коде я вызываю requestPermissions метод класса Dialog Fragment. Поэтому я ожидаю получить результат в том же классе.

Любая помощь приветствуется. Спасибо заранее!


EDIT: Здесь я добавляю более подробную информацию, чтобы она была более полезной для других. Раньше я использовал getChildFragmentManager(), чтобы показать диалоговое окно.

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getChildFragmentManager(), "Contact Picker");

Но As @CommonWare попросил меня использовать активность, чтобы показать DialogFragment. Я сделал следующие изменения, и он работает.

ContactPickerDialog dialog = new ContactPickerDialog();
dialog.show(getActivity().getSupportFragmentManager(), "Contact Picker");
4b9b3361

Ответ 1

Как представляется, ошибка в Android, где вложенные фрагменты не поддерживают обратный вызов onRequestPermissionsResult(). Для DialogFragment обходным путем представляется, что фрагмент, желающий показать диалог, вызывает метод для хостинговой активности, а активность показывает сам DialogFragment.

Ответ 3

Этот issue кажется исправленным в Android Support Library 23.3.0 и выше.

Если вы используете Фрагменты поддержки v4, вложенные фрагменты теперь будут получать обратные вызовы к onRequestPermissionsResult().

Изменить: @AndrewS, здесь, как вы можете обновить.

В вашем файле build.gradle(app) измените следующую строку, чтобы использовать самую последнюю версию библиотеки поддержки 24.0.0, которая является последней версией:

dependencies {
    compile 'com.android.support:appcompat-v7:24.0.0'
}

Ответ 4

РЕДАКТИРОВАТЬ:

Я предлагаю использовать новую версию Support Library 23.3.0, потому что исправленная проблема Google не вызывает onRequestPermissionsResult, но если по каким-то причинам вам нужно использовать более старую версию, то см. Исходный ответ ниже.

ОРИГИНАЛЬНЫЙ ОТВЕТ:

Я использую следующее обходное решение (вместе с библиотекой easyPermissions):

BaseFragment:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    /** child v4.fragments aren't receiving this due to bug. So forward to child fragments manually
     * https://code.google.com/p/android/issues/detail?id=189121
     */
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    List<Fragment> fragments = getChildFragmentManager().getFragments();
    if (fragments != null) {
        // it is possible that fragment might be null in FragmentManager
        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grantResults);
            }
        }
    }
}

BaseActivity:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    Fragment fragment = getSupportFragmentManager().findFragmentById(getFragmentContainer())
    if (fragment != null) {
        fragment.onRequestPermissionsResult(requestCode&0xff, permissions, grantResults);
    }
}

Использование:

public class SomeFragment extends BaseFragment implements EasyPermissions.PermissionCallbacks {
    private static final int PICK_CONTACT = 1;
    private static final int READ_CONTACTS_PERM = 2;

    // some code

    @AfterPermissionGranted(READ_CONTACTS_PERM)
    private void pickContactWithPermissionsCheck() {
        if (EasyPermissions.hasPermissions(getContext(), Manifest.permission.READ_CONTACTS)) {
            // Have permission
            pickContactForResult();
        } else {
            // Request one permission
            EasyPermissions.requestPermissions(this, getString(R.string.read_contacts_permission_explanation),
                    READ_CONTACTS_PERM, Manifest.permission.READ_CONTACTS);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);

        // FIXME problem with incorrect requestCode coming to callback for Nested fragments
        // More information here - https://code.google.com/p/android/issues/detail?id=189121
        if (isVisible() && Arrays.asList(permissions).contains(Manifest.permission.READ_CONTACTS)) {
            requestCode = READ_CONTACTS_PERM;
        }

        // EasyPermissions handles the request result.
        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }
}

Ответ 5

Одна вещь, которая помогла мне, была в этом. Когда вы запрашиваете разрешение от вложенного фрагмента, используйте getParent так

 fragment.getParentFragment().requestPermissions((new String[]
              {Manifest.permission.READ_CONTACTS}), requestCode);

а затем переопределите родительский фрагмент onRequestPermissionResult и проверьте соответствующий код запроса.

Надеюсь, он вам тоже поможет.

Ответ 6

Если у вас есть проблема с вложенным фрагментом, вы можете запросить разрешение от родительского фрагмента

getParentFragment().requestPermissions(new String[]{permission}, requestCode);

а затем переадресовать обратный вызов дочернему фрагменту

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grants) {
    List<Fragment> fragments = getChildFragmentManager().getFragments();
    if (fragments != null) {
        for (Fragment fragment : fragments) {
            if (fragment != null) {
                fragment.onRequestPermissionsResult(requestCode, permissions, grants);
            }
        }
    }
}

Ответ 7

У меня была эта проблема без вложенных фрагментов, где активность показывала фрагмент диалога, и результат не получался.

Добавление super.onRequestPermissionsResult(requestCode, permissions, grantResults);
к деятельности onRequestPermissionsResult() решил проблему.

Ответ 8

Я сделал это так:

public class DialogFragmentSMS extends DialogFragment implements View.OnClickListener {

public static DialogFragmentSMS frag;
private static View view;
private static ViewGroup parent;
private EditText editTextMensagem;
private String celular;

private final static int SMS_REQUEST = 20;

public DialogFragmentSMS() {

}
public static DialogFragmentSMS newInstance(String celular)
{

    Bundle args = new Bundle();
    args.putString("celular", celular);
    frag = new DialogFragmentSMS();
    frag.setArguments(args);
    return frag;
}

@Override
public void onCreate(Bundle saveInstaceState)
{
    super.onCreate(saveInstaceState);
}

    @Override
public void onClick(View v) {
    if (!PermissaoUtils.hasPermission(getActivity(), Manifest.permission.SEND_SMS)) {
        //PermissaoUtils.requestPermissions(getActivity(), new String[]{Manifest.permission.SEND_SMS}, SMS_REQUEST);
        frag.requestPermissions(new String[]{Manifest.permission.SEND_SMS}, SMS_REQUEST);
    }else{
        if (validaCampos()) {
            SmsManager smsManager = SmsManager.getDefault();
            smsManager.sendTextMessage("0" + celular, null, editTextMensagem.getText().toString(), null, null);
            Toast.makeText(getActivity(), R.string.sms_enviado, Toast.LENGTH_SHORT).show();
            getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
            frag.dismiss();
        }
    }
}

Разрешение моего класса

public class PermissaoUtils
{
    public static boolean useRunTimePermissions() {
        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
    }

    public static boolean hasPermission(Activity activity, String permission) {
        if (useRunTimePermissions()) {
            return activity.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
        }
        return true;
    }

    public static void requestPermissions(Activity activity, String[] permission, int requestCode) {
        if (useRunTimePermissions()) {
            activity.requestPermissions(permission, requestCode);
        }
    }
}

Ответ 9

Если вы посмотрите на документацию метода requestPermissions фрагмента, вы обнаружите, что вам еще нужно объявить разрешения в вашем манифесте:

enter image description here

Если это не так, то фрагмент own onRequestPermissionsResult не будет вызываться.

Вместо этого onRequestPermissionsResult действие onRequestPermissionsResult но не будет иметь никакого эффекта.

Так что разрешение разрешения внутри фрагмента должно выполняться следующим образом:

1. Объявите разрешение в вашем манифесте

<uses-permission android:name="android.permission.CAMERA"/>

Введите это перед тегом приложения.

2. Проверьте разрешение в вашем фрагменте

if (ActivityCompat.checkSelfPermission(context, permission) 
        != PackageManager.PERMISSION_GRANTED) {

    requestPermissions(
        arrayOf(Manifest.permission.CAMERA), 
        REQUEST_CODE_CAMERA_PERMISSION)
}

3. Подождите, пока результат разрешения в вашем фрагменте

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    when (requestCode) {
        REQUEST_CODE_CAMERA_PERMISSION -> { 

        val granted = grantResults.isNotEmpty()
            && permissions.isNotEmpty()
            && grantResults[0] == PackageManager.PERMISSION_GRANTED
            && !ActivityCompat.shouldShowRequestPermissionRationale(activity, permissions[0])    

        when (granted) {
            true -> openCamera()
            else -> proceedWithoutPermission()
        }
    }
}

4. Убедитесь, что вы не переопределяете действие onRequestPermissionsResult

Переопределение активности onRequestPermissionsResult приведет к тому, что фрагмент не будет реагировать.

Ответ 10

В дополнение к конечной части ответа Nino Handler и для тех, кто все еще имеет проблемы с этим, убедитесь, что если вы переопределите onRequestPermissionsResult в родительской активности/фрагменте фрагмента диалога, вы вызываете super.onRequestPermissionsResult.

Я переопределял onRequestPermissionsResult в родительской активности моего фрагмента диалога, но пренебрегал вызовом супер-метода. Как только я изменил его, чтобы вызвать метод super, он должным образом делегирован в onRequestPermissionsResult в моем фрагменте диалога.

Ответ 11

Если вы вызываете DialogFragment из фрагмента, используйте это:

YourDialogFragment dialogFragment = YourDialogFragment.newInstance();
dialogFragment.show(getActivity().getFragmentManager(), YourDialogFragment.TAG);
dialogFragment.setParentFragment(this);

Также напишите в фрагменте:

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        ...
    }
}

В YourDialogFragment напишите дополнительный метод для передачи родительского фрагмента:

public void setParentFragment(Fragment fragment) {
    this.fragment = fragment;
}

Позже в YourDialogFragment при запросе разрешения вызывается:

if (fragment != null) {
    fragment.requestPermissions(new String[]{permission}, REQUEST_CODE);
}