Fragment#requestPermissions() でハマった

Android M から新しいパーミッションモデルになり、アプリから一部のパーミッションの権限を要求することが可能になりました。この実装を調べていてハマったところがあるので共有します。

パーミッション権限を要求するときは以下のような感じです。

[公式](https://developer.android.com/preview/features/runtime-permissions.html)には、 `Activity#requestPermissions()` を呼び出して、要求結果を `Activity#onRequestPermissionsResult()` で受け取る、と書いてあります。

```java
if (checkSelfPermission(Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
    requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant

    return;
}

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! do the
                // calendar task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'switch' lines to check for other
        // permissions this app might request
    }
}
```

## ハマったところ

### 1. Fragment にも requestPermissions() はある

@hotchemi のおかげで Fragment にも `requestPermissions()` が実装されてるのを知りました。[公式](https://developer.android.com/preview/features/runtime-permissions.html)を見る限り `Activity` だけにしか無いように見えるのつらい...

Android M Preview 版のソースコードを見ると、ちゃんと `requestPermissions()` と `onRequestPermissionsResult()` が実装されていることが分かりました。

なので、安心して Fragment でパーミッション要求を実装できそうですね！！！！！！！！

```java
package android.app;

public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListener {

    public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        Intent intent =
                mHost.getContext().getPackageManager().buildRequestPermissionsIntent(permissions);
        mHost.onStartActivityFromFragment(this, intent, requestCode, null);
    }

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        /* callback - do nothing */
    }
```

### 2. Fragment に requestPermissions() はなかった

タイトル詐欺です。

Fragment に `requestPermissions()` があるとのことなので、満身創痍で App Permission のサンプルを実装していましたが、コード補完に `requestPermissions()` が候補リストに出てきませんでした！！！！！！！！！！！！！！！！

![スクリーンショット 2015-06-29 16.46.34.png](https://qiita-image-store.s3.amazonaws.com/0/35834/984cd54c-22cf-ff62-1177-7c7171c9b4d1.png)

「うーーーん......うーーーん......」と時間を無駄に消費したのですが、原因はすごく簡単に解決できるものでした。

**まちがい**

```java
import android.support.v4.app.Fragment;

public class PermissionFragment extends Fragment {

    private void requestReadContactsPermission() {
        requestPermissions(
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    }
```

**せいかい**

```java
import android.app.Fragment;

public class PermissionFragment extends Fragment {

    private void requestReadContactsPermission() {
        requestPermissions(
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);
    }
```

## まとめ

現状はイカのどれかで対処する必要があります。

* `android.app.Fragment` のほうを import する
* support v4 のアップデートを待つ
* `Activity` のほうで実装

無駄にハマった...

## 追記 7/13

support v4 のソースコードを見たら

```java
    public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mHost.onRequestPermissionsFromFragment(this, permissions,requestCode);
    }

    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        /* callback - do nothing */
    }

    public boolean shouldShowRequestPermissionRationale(@NonNull String permission) {
        if (mHost != null) {
            return mHost.onShouldShowRequestPermissionRationale(permission);
        }
        return false;
    }
```

のように、ちゃんと実装されていました。なので、安心して v4 を使えますね。