Skip to content

Commit

Permalink
Fixed compilation and potential crashes on Android M when the Fragmen…
Browse files Browse the repository at this point in the history
…t was recreated using the default ctor
  • Loading branch information
Over17 committed Oct 24, 2017
1 parent 8bb727d commit 92e1a33
Showing 1 changed file with 11 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class PermissionFragment extends Fragment

public PermissionFragment()
{
m_ResultCallbacks = null;
}

public PermissionFragment(final UnityAndroidPermissions.IPermissionRequestResult resultCallbacks)
Expand All @@ -25,8 +26,15 @@ public PermissionFragment(final UnityAndroidPermissions.IPermissionRequestResult
@Override public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
String[] permissionNames = getArguments().getStringArray(PERMISSION_NAMES);
requestPermissions(permissionNames, PERMISSIONS_REQUEST_CODE);
if (m_ResultCallbacks == null)
{
getFragmentManager().beginTransaction().remove(this).commit();
}
else
{
String[] permissionNames = getArguments().getStringArray(PERMISSION_NAMES);
requestPermissions(permissionNames, PERMISSIONS_REQUEST_CODE);
}
}

@Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
Expand All @@ -42,7 +50,7 @@ public PermissionFragment(final UnityAndroidPermissions.IPermissionRequestResult
m_ResultCallbacks.OnPermissionDenied(permissions[i]);
}

FragmentTransaction fragmentTransaction = getActivity().getFragmentManager().beginTransaction();
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
fragmentTransaction.remove(this);
fragmentTransaction.commit();
}
Expand Down

3 comments on commit 92e1a33

@sjvc
Copy link

@sjvc sjvc commented on 92e1a33 Dec 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! When the fragment is automatically recreated? If this occurs, would be better to save instance state and then restore it, to request again permissions when it gets recreated?

@Over17
Copy link
Owner Author

@Over17 Over17 commented on 92e1a33 Dec 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi!
For example, when you pause the app when showing the fragment, and then resume it.
It would be better to save the state if possible - not sure if it's possible to handle with the permission request/callback though.
Your suggestions/PRs are welcome!

@sjvc
Copy link

@sjvc sjvc commented on 92e1a33 Dec 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your fast response. I've made this sightly modified version of your permission manager:

public class PermissionManager {

    private static final int PERMISSIONS_REQUEST_CODE = 15887;

    private static final String UNITY_PERMISSION_GRANTED_CALLBACK_METHOD_NAME = "OnPermissionGranted";
    private static final String UNITY_PERMISSION_DENIED_CALLBACK_METHOD_NAME = "OnPermissionDenied";

    public boolean isPermissionGranted (Activity activity, String permissionName) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        }

        return activity != null && activity.checkSelfPermission(permissionName) == PackageManager.PERMISSION_GRANTED;
    }

    public void requestPermissionAsync(Activity activity, final String[] permissionNames, final String unityCallbackGameObjectName) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            if (unityCallbackGameObjectName != null){
                for (int i = 0; i < permissionNames.length && i < permissionNames.length; ++i) {
                    UnityPlayer.UnitySendMessage(unityCallbackGameObjectName, UNITY_PERMISSION_GRANTED_CALLBACK_METHOD_NAME, permissionNames[i]);
                }
            }

            return;
        }

        if (activity == null || permissionNames == null) {
            return;
        }

        final Fragment fragment = PermissionsFragment.newInstance(permissionNames, unityCallbackGameObjectName);
        activity.getFragmentManager().beginTransaction().add(0, fragment).commit();
    }

    public static class PermissionsFragment extends Fragment {
        private String[] mPermissionNames;
        private String mUnityCallbackGameObjectName = null;

        public static PermissionsFragment newInstance(String[] permissionNames, String unityCallbackGameObjectName){
            PermissionsFragment fragment = new PermissionsFragment();
            fragment.setArgs(permissionNames, unityCallbackGameObjectName);
            return fragment;
        }

        public void setArgs(String[] permissionNames, String unityCallbackGameObjectName){
            mPermissionNames = permissionNames;
            mUnityCallbackGameObjectName = unityCallbackGameObjectName;
        }

        @TargetApi(Build.VERSION_CODES.M)
        @Override public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            if (savedInstanceState != null) {
                mPermissionNames = savedInstanceState.getStringArray("permissions");
                mUnityCallbackGameObjectName = savedInstanceState.getString("callbackGameObjectName");
            }

            requestPermissions(mPermissionNames, PERMISSIONS_REQUEST_CODE);
        }

        @Override
        public void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);

            outState.putStringArray("permissions", mPermissionNames);
            outState.putString("callbackGameObjectName", mUnityCallbackGameObjectName);
        }

        @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
            if (requestCode != PERMISSIONS_REQUEST_CODE)
                return;

            if (mUnityCallbackGameObjectName != null) {
                for (int i = 0; i < permissions.length && i < grantResults.length; ++i) {
                    if (grantResults[i] == PackageManager.PERMISSION_GRANTED)
                        UnityPlayer.UnitySendMessage(mUnityCallbackGameObjectName, UNITY_PERMISSION_GRANTED_CALLBACK_METHOD_NAME, permissions[i]);
                    else
                        UnityPlayer.UnitySendMessage(mUnityCallbackGameObjectName, UNITY_PERMISSION_DENIED_CALLBACK_METHOD_NAME, permissions[i]);
                }
            }

            getFragmentManager().beginTransaction().remove(this).commit();
        }
    }
}

As you can see, I'm not using IPermissionRequestResult, but a simple string for the callback, so it can be saved in the Bundle object.

RequestPermission method in C# is like this:

    public static void RequestPermission(string[] permissionNames, string callbackGameObjectName){
        GetPermissionsService().Call("requestPermissionAsync", GetActivity(), permissionNames, callbackGameObjectName);
    }

And in the GameObject with name callbackGameObjectName, you must have two callback methods:

    public void OnPermissionGranted(string permission){}
    public void OnPermissionDenied(string permission){}

In order to use UnityPlayer.UnitySendMessage you have to include Unity's classes.jar file in your Android module libs folder. You can find it in C:\Program Files\Unity\Editor\Data (/Applications/Unity on Mac) in a subfolder called PlaybackEngines/AndroidPlayer/Variations/mono or il2cpp/Development or Release/Classes/. In your module build.grade file, you have include using this:

dependencies {
    provided files('./libs/classes.jar')
}

By using "provided", classes.jar will not be added to the aar file, so you will avoid redundancy, and it's not needed.

What do you think about it?

Please sign in to comment.