15

I play around with the Preview M and test my app on it, especially the "saving a file to external storage" part. Before the download/save process starts, i request for

  Manifest.permission.WRITE_EXTERNAL_STORAGE

permission as described on the developer page: https://developer.android.com/preview/features/runtime-permissions.html

The dialog occurs as expected:

"Allow <AppName> to access photos, media, and files on your device?" Deny / Allow

If i hit the "deny"-button, the onRequestPermissionsResult-method of the activity is called.

If i press the "allow"-button, the activity is first recreated and afterwards the onRequestPermissionsResult-method is called. I think it's a result of the granted permission.

But the second situation is tricky because i want to trigger a callback that starts the download, but this object is null at this point:

public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {

    getLogger().error("onRequestPermissionsResult ( " + requestCode + ", " + permissions + ", " + grantResults + " )");
    switch (requestCode) {


        //permission for saving files?
        case PermissionCode.WRITE_EXTERNAL_STORAGE: {


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

                //HERE IS THE NULL-OBJECT 
                if (controller != null) {

                    controller.triggerCallback();
                }
            }
            break;
        }
        default: {

            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }
}

So my questions are:

  1. Can I avoid this recreation?
  2. If no, how can i redesign my code to solve the problem - i'm totally idealess at the moment

EDIT 1:

I tried to solve the problem with a handler and postDelayed - but i skipped it.

EDIT 2:

I preliminary solved it and show a Toast to user with the request to push the download button again (in case of granted permission). But Google: ARE YOU SERIOUS?

EDIT 3:

No recreation happens with the latest SDK 6.0 (Version 23) - maybe somebody heard my weeping in Mountain View :-)

A.D.
  • 1,412
  • 2
  • 19
  • 37
  • Hey how did you sove it eventually? I am compiling with version 23 too, and I am still facing activity restarts on permission allow and deny. The onRequestPermissionsResult method is never called. I am calling requestPermissions() from a fragment. Does that make any difference? – Mayur More Oct 20 '15 at 08:07
  • @Mayur More: how do you revoke/grant the permission? When revoking/granting inside app settings, i still have recreation after resuming to app. But inside app workflow - as described above - no recreation occurs... – A.D. Oct 21 '15 at 13:00
  • 3
    I'm still observing this recreation as of Jan 2016. – afathman Jan 13 '16 at 18:29
  • I am facing this issue when I DENY the permission. Working fine for ALLOW the permission. – Smeet Mar 30 '16 at 12:29

2 Answers2

1

You can always check the download condition immediately after the activity recreates itself in onCreate():

static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 0;
boolean initiateDownload = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if(savedInstanceState != null) {
        initiateDownload = savedInstanceState.getBoolean("toDownload");
    }
}

@Override
public void onResume() {
    super.onResume();
    final boolean hasPermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            == PackageManager.PERMISSION_GRANTED;
    if(initiateDownload && hasPermission) {
        // start download here...
    } else {
        requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
                MainActivity.MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if(requestCode == MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) {
        if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            initiateDownload = true;
        } else {
            // denied permission...
        }
    }
}

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putBoolean("toDownload", initiateDownload);
}
Neoh
  • 15,906
  • 14
  • 66
  • 78
0

Android may destroy and recreate your activity for a number of reasons. The use case of requesting permissions is no exception. You can use your preferred way of saving and restoring UI state. If your state is parcelable you can do it like the example below. Why this is not mentioned in Request App Permissions or Android RuntimePermissions Sample I don't know.

See more in Saving and restoring transient UI state and Saving UI States

public class ExampleActivity extends AppCompatActivity {
    private static final String CURRENT_DOWNLOAD_ITEM = "CURRENT_DOWNLOAD_ITEM";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (savedInstanceState != null)
            currentDownloadItem = savedInstanceState.getParcelable(CURRENT_DOWNLOAD_ITEM);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putParcelable(CURRENT_DOWNLOAD_ITEM, currentDownloadItem);
        super.onSaveInstanceState(outState);
    }

    public void downloadItem(Parcelable item) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            currentDownloadItem = item;
            requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
        } else
            perfornDownload(item);
    }

    private Parcelable currentDownloadItem;

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    if (currentDownloadItem != null) {
                        perfornDownload(currentDownloadItem);
                        currentDownloadItem = null;
                    } else
                        Toast.makeText(this, "Please select download again now that we have permission to save it", Toast.LENGTH_LONG).show();
                } else
                    Toast.makeText(this, "Download cancelled, as we don\'t have permission to save the downloaded files", Toast.LENGTH_LONG).show();
                break;
        }
    }

    private void perfornDownload(Parcelable item) {
        // Here we are sure we have the permission
    }
}
user1801374
  • 378
  • 1
  • 10