diff --git a/library/build.gradle b/library/build.gradle index a5b89ff..6882dd3 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -11,7 +11,7 @@ android { minSdkVersion 15 targetSdkVersion 25 versionCode 1 - versionName "1.0" + versionName "1.1.1" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -42,7 +42,7 @@ dependencies { publish { groupId = 'ru.alexbykov' artifactId = 'nopermission' - publishVersion = '1.1.0' + publishVersion = '1.1.1' desc = 'Permission library for Android' licences = ['Apache-2.0'] website = 'https://github.com/NoNews/NoPermission' diff --git a/library/src/main/java/ru/alexbykov/nopermission/PermissionHelper.java b/library/src/main/java/ru/alexbykov/nopermission/PermissionHelper.java index c1d7796..591ecb6 100644 --- a/library/src/main/java/ru/alexbykov/nopermission/PermissionHelper.java +++ b/library/src/main/java/ru/alexbykov/nopermission/PermissionHelper.java @@ -2,10 +2,16 @@ import android.annotation.SuppressLint; import android.app.Activity; +import android.content.Context; +import android.content.Intent; import android.content.pm.PackageManager; +import android.net.Uri; import android.os.Build; +import android.provider.Settings; import android.support.annotation.RequiresApi; import android.support.v4.app.ActivityCompat; +import android.support.v4.app.Fragment; +import android.support.v7.app.AppCompatActivity; import java.util.ArrayList; import java.util.List; @@ -22,8 +28,9 @@ public class PermissionHelper { - private static final int PERMISSION_REQUEST_CODE = 1005001; + private static final int PERMISSION_REQUEST_CODE = 98; private Activity activity; + private Fragment fragment; private String[] permissions; private Runnable successListener; private Runnable deniedListener; @@ -33,9 +40,14 @@ public PermissionHelper(Activity activity) { this.activity = activity; } + public PermissionHelper(Fragment fragment) { + this.fragment = fragment; + } + /** * @param permission is single permission, which you want to ask + * @return current object */ public PermissionHelper check(String permission) { this.permissions = new String[1]; @@ -46,6 +58,7 @@ public PermissionHelper check(String permission) { /** * @param permissions is array of permissions, which you want to ask + * @return current object */ public PermissionHelper check(String... permissions) { this.permissions = permissions; @@ -57,6 +70,7 @@ public PermissionHelper check(String... permissions) { * Setup failure callback * * @param listener called when user deny permission + * @return current object */ public PermissionHelper onSuccess(Runnable listener) { this.successListener = listener; @@ -67,6 +81,7 @@ public PermissionHelper onSuccess(Runnable listener) { * Setup failure callback * * @param listener called when user deny permission + * @return current object */ public PermissionHelper onDenied(Runnable listener) { this.deniedListener = listener; @@ -75,9 +90,10 @@ public PermissionHelper onDenied(Runnable listener) { /** - * Setup never ask again callback + * This method setup never ask again callback * * @param listener called when permission in status "never ask again" + * @return current object */ public PermissionHelper onNeverAskAgain(Runnable listener) { this.neverAskAgainListener = listener; @@ -86,7 +102,7 @@ public PermissionHelper onNeverAskAgain(Runnable listener) { /** - * Check API-version and listeners + * This method check API-version and listeners * * @throws RuntimeException if isListenersCorrect return false */ @@ -94,10 +110,15 @@ public void run() { if (isListenersCorrect()) { runSuccessOrAskPermissions(); } else { - throw new RuntimeException("OnPermissionSuccessListener or OnPermissionFailureListener not installed. Please, use onSuccess and onDenied methods"); + throw new RuntimeException("permissionSuccessListener or permissionDeniedListener have null reference. You must realize onSuccess and onDenied methods"); } } + + /** + * This method run successListener if all permissions granted, + * and run method checkPermissions, if needToAskPermissions return false + */ private void runSuccessOrAskPermissions() { if (isNeedToAskPermissions()) { checkPermissions(); @@ -108,22 +129,33 @@ private void runSuccessOrAskPermissions() { /** - * Request only those permissions that are not granted. - * If all are granted, the success method is triggered + * This method request only those permissions that are not granted. + * If all are granted, success callback called */ @RequiresApi(api = Build.VERSION_CODES.M) private void checkPermissions() { final String[] permissionsForRequest = getPermissionsForRequest(); if (permissionsForRequest.length > 0) { - activity.requestPermissions(permissionsForRequest, PERMISSION_REQUEST_CODE); + askPermissions(permissionsForRequest); } else { successListener.run(); } } + @SuppressLint("NewApi") + private void askPermissions(String[] permissionsForRequest) { + if (activity != null) { + activity.requestPermissions(permissionsForRequest, PERMISSION_REQUEST_CODE); + } else { + fragment.requestPermissions(permissionsForRequest, PERMISSION_REQUEST_CODE); + } + } + /** - * Check listeners for null + * This method check listeners for null + * + * @return true if you realized method onSuccess and onDenied */ private boolean isListenersCorrect() { return successListener != null && deniedListener != null; @@ -131,7 +163,9 @@ private boolean isListenersCorrect() { /** - * We need to ask permission only if API >=23 + * This method ckeck api version + * + * @return true if API >=23 */ private boolean isNeedToAskPermissions() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; @@ -203,7 +237,11 @@ private void runNeverAskAgain() { * @return true if permission granted and false if permission not granted */ private boolean isPermissionNotGranted(String permission) { - return ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED; + if (activity != null) { + return ActivityCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED; + } else { + return ActivityCompat.checkSelfPermission(fragment.getContext(), permission) != PackageManager.PERMISSION_GRANTED; + } } @@ -213,16 +251,40 @@ private boolean isPermissionNotGranted(String permission) { */ @RequiresApi(api = Build.VERSION_CODES.M) private boolean isNeverAskAgain(String permission) { - return !activity.shouldShowRequestPermissionRationale(permission); + if (activity != null) { + return !activity.shouldShowRequestPermissionRationale(permission); + } else { + return !fragment.shouldShowRequestPermissionRationale(permission); + } } + /** - * To avoid memory leaks, you must change reference to null + * This method start application settings activity + * Note: is not possible to open at once screen with application permissions. + */ + public void startApplicationSettingsActivity() { + final Context context = activity == null ? fragment.getContext() : activity; + final Intent intent = new Intent(); + final Uri uri = Uri.fromParts("package", context.getPackageName(), null); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(uri); + context.startActivity(intent); + } + + /** + * This method change listeners reference to avoid memory leaks */ public void unsubscribe() { - activity = null; deniedListener = null; successListener = null; + + if (activity != null) { + activity = null; + } + if (fragment != null) { + fragment = null; + } if (neverAskAgainListener != null) { neverAskAgainListener = null; } diff --git a/sample/build.gradle b/sample/build.gradle index 78dd69a..49c16e9 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -13,17 +13,27 @@ android { testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + jackOptions { + enabled true + } } + + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:support-v4:26.1.0' androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 68aad1e..f5af2da 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,10 +1,10 @@ + package="ru.alexbykov.permissionssample"> - - - + + + + + + + + + + + - + - + + diff --git a/sample/src/main/java/ru/alexbykov/permissionssample/MainActivity.java b/sample/src/main/java/ru/alexbykov/permissionssample/MainActivity.java index 2a7533f..2ca2af5 100644 --- a/sample/src/main/java/ru/alexbykov/permissionssample/MainActivity.java +++ b/sample/src/main/java/ru/alexbykov/permissionssample/MainActivity.java @@ -1,75 +1,35 @@ package ru.alexbykov.permissionssample; -import android.Manifest; -import android.os.Bundle; -import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.View; -import android.widget.TextView; +import android.os.Bundle; -import ru.alexbykov.nopermission.PermissionHelper; +import ru.alexbykov.permissionssample.fragments.ChooseFragment; public class MainActivity extends AppCompatActivity { - private final String TAG = "PermissionResult: "; private static final int LAYOUT = R.layout.activity_main; - private PermissionHelper permissionHelper; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(LAYOUT); - setupPermissionHelper(); - setupUX(); - } - - - private void setupUX() { - findViewById(R.id.btnAskPermission).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - askLocationPermission(); - } - }); + startFragment(ChooseFragment.newInstance(), false); } - private void askLocationPermission() { - permissionHelper.check(Manifest.permission.ACCESS_COARSE_LOCATION).onSuccess(new Runnable() { - @Override - public void run() { - Log.d(TAG, "LocationSuccess"); - ((TextView) findViewById(R.id.tvResult)).setText(R.string.result_success); - } - }).onDenied(new Runnable() { - @Override - public void run() { - Log.d(TAG, "LocationDenied"); - ((TextView) findViewById(R.id.tvResult)).setText(R.string.result_failure); - } - }).onNeverAskAgain(new Runnable() { - @Override - public void run() { - Log.d(TAG, "LocationNeverAskAgain"); - ((TextView) findViewById(R.id.tvResult)).setText(R.string.result_never_ask_again); - } - }).run(); - } + public void startFragment(Fragment fragment, boolean addToBackStack) { - private void setupPermissionHelper() { - permissionHelper = new PermissionHelper(this); + FragmentTransaction transaction = + getSupportFragmentManager() + .beginTransaction() + .replace(R.id.lt_container, fragment); + if (addToBackStack) { + transaction.addToBackStack(fragment.getTag()); + } + transaction.commit(); } - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - - @Override - protected void onDestroy() { - permissionHelper.unsubscribe(); - super.onDestroy(); - } } diff --git a/sample/src/main/java/ru/alexbykov/permissionssample/activities/LocationSampleActivity.java b/sample/src/main/java/ru/alexbykov/permissionssample/activities/LocationSampleActivity.java new file mode 100644 index 0000000..d4d2fac --- /dev/null +++ b/sample/src/main/java/ru/alexbykov/permissionssample/activities/LocationSampleActivity.java @@ -0,0 +1,79 @@ +package ru.alexbykov.permissionssample.activities; + +import android.Manifest; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.util.Log; +import android.widget.TextView; + +import ru.alexbykov.nopermission.PermissionHelper; +import ru.alexbykov.permissionssample.R; + +public class LocationSampleActivity extends AppCompatActivity { + + + private final String TAG = "PermissionResult: "; + private static final int LAYOUT = R.layout.activity_location_sample; + private PermissionHelper permissionHelper; + private TextView tvResult; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(LAYOUT); + setupPermissionHelper(); + setupUI(); + setupUX(); + } + + private void setupUI() { + tvResult = findViewById(R.id.tv_result); + } + + + private void setupUX() { + findViewById(R.id.btnAskPermission).setOnClickListener(view -> askLocationPermission()); + } + + private void askLocationPermission() { + permissionHelper.check(Manifest.permission.ACCESS_COARSE_LOCATION) + .onSuccess(this::onSuccess) + .onDenied(this::onDenied) + .onNeverAskAgain(this::onNeverAskAgain) + .run(); + } + + + private void onSuccess() { + Log.d(TAG, "LocationSuccess"); + tvResult.setText(R.string.result_success); + } + + + private void onNeverAskAgain() { + Log.d(TAG, "LocationNeverAskAgain"); + tvResult.setText(R.string.result_never_ask_again); + } + + private void onDenied() { + Log.d(TAG, "LocationDenied"); + tvResult.setText(R.string.result_denied); + permissionHelper.startApplicationSettingsActivity(); + } + + private void setupPermissionHelper() { + permissionHelper = new PermissionHelper(this); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + protected void onDestroy() { + permissionHelper.unsubscribe(); + super.onDestroy(); + } +} diff --git a/sample/src/main/java/ru/alexbykov/permissionssample/fragments/ChooseFragment.java b/sample/src/main/java/ru/alexbykov/permissionssample/fragments/ChooseFragment.java new file mode 100644 index 0000000..978b99a --- /dev/null +++ b/sample/src/main/java/ru/alexbykov/permissionssample/fragments/ChooseFragment.java @@ -0,0 +1,57 @@ +package ru.alexbykov.permissionssample.fragments; + + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import ru.alexbykov.permissionssample.MainActivity; +import ru.alexbykov.permissionssample.R; +import ru.alexbykov.permissionssample.activities.LocationSampleActivity; + +/** + * A simple {@link Fragment} subclass. + */ +public class ChooseFragment extends Fragment { + + + private static final int LAYOUT = R.layout.fragment_choose; + + private View view; + + public static Fragment newInstance() { + return new ChooseFragment(); + } + + + public ChooseFragment() { + // Required empty public constructor + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + view = inflater.inflate(LAYOUT, container, false); + setupUX(); + return view; + } + + private void setupUX() { + view.findViewById(R.id.btn_activity_sample).setOnClickListener(v -> onClickActivitySample()); + view.findViewById(R.id.btn_fragment_sample).setOnClickListener(v -> onClickFragmentSample()); + } + + private void onClickFragmentSample() { + ((MainActivity)getActivity()).startFragment(LocationSampleFragment.newInstance(),true); + } + + private void onClickActivitySample() { + startActivity(new Intent(getContext(), LocationSampleActivity.class)); + } + +} diff --git a/sample/src/main/java/ru/alexbykov/permissionssample/fragments/LocationSampleFragment.java b/sample/src/main/java/ru/alexbykov/permissionssample/fragments/LocationSampleFragment.java new file mode 100644 index 0000000..be8f61b --- /dev/null +++ b/sample/src/main/java/ru/alexbykov/permissionssample/fragments/LocationSampleFragment.java @@ -0,0 +1,98 @@ +package ru.alexbykov.permissionssample.fragments; + + +import android.Manifest; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import ru.alexbykov.nopermission.PermissionHelper; +import ru.alexbykov.permissionssample.R; + +/** + * A simple {@link Fragment} subclass. + */ +public class LocationSampleFragment extends Fragment { + + + private static final int LAYOUT = R.layout.activity_location_sample; + private final String TAG = "PermissionResult: "; + private View view; + private TextView tvResult; + private PermissionHelper permissionHelper; + + public static Fragment newInstance() { + return new LocationSampleFragment(); + } + + + public LocationSampleFragment() { + // Required empty public constructor + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + view = inflater.inflate(LAYOUT, container, false); + setupPermissionHelper(); + setupUI(); + setupUX(); + return view; + } + + private void setupUI() { + tvResult = view.findViewById(R.id.tv_result); + } + + + private void setupUX() { + view.findViewById(R.id.btnAskPermission).setOnClickListener(view -> askLocationPermission()); + } + + private void askLocationPermission() { + permissionHelper.check(Manifest.permission.ACCESS_COARSE_LOCATION) + .onSuccess(this::onSuccess) + .onDenied(this::onDenied) + .onNeverAskAgain(this::onNeverAskAgain) + .run(); + } + + + private void onSuccess() { + Log.d(TAG, "LocationSuccess"); + tvResult.setText(R.string.result_success); + } + + + private void onNeverAskAgain() { + Log.d(TAG, "LocationNeverAskAgain"); + tvResult.setText(R.string.result_never_ask_again); + permissionHelper.startApplicationSettingsActivity(); + } + + private void onDenied() { + Log.d(TAG, "LocationDenied"); + tvResult.setText(R.string.result_denied); + } + + private void setupPermissionHelper() { + permissionHelper = new PermissionHelper(this); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + permissionHelper.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + + @Override + public void onDestroy() { + permissionHelper.unsubscribe(); + super.onDestroy(); + } +} diff --git a/sample/src/main/res/layout/activity_location_sample.xml b/sample/src/main/res/layout/activity_location_sample.xml new file mode 100644 index 0000000..6e1d66f --- /dev/null +++ b/sample/src/main/res/layout/activity_location_sample.xml @@ -0,0 +1,27 @@ + + + +