Skip to content

Commit c72b4a3

Browse files
author
Rafael Araujo
committed
Example with Java.
1 parent 811b6fd commit c72b4a3

File tree

2 files changed

+348
-2
lines changed

2 files changed

+348
-2
lines changed
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
package com.orafaaraujo.androiddevconference2017.helper;
2+
3+
import android.Manifest;
4+
import android.content.Context;
5+
import android.content.DialogInterface;
6+
import android.content.Intent;
7+
import android.content.pm.PackageManager;
8+
import android.net.Uri;
9+
import android.os.Bundle;
10+
import android.provider.Settings;
11+
import android.support.annotation.NonNull;
12+
import android.support.annotation.Nullable;
13+
import android.support.v4.app.DialogFragment;
14+
import android.support.v4.app.Fragment;
15+
import android.support.v4.app.FragmentManager;
16+
import android.support.v4.content.ContextCompat;
17+
import android.support.v7.app.AlertDialog;
18+
import android.util.Log;
19+
20+
import com.orafaaraujo.androiddevconference2017.R;
21+
22+
import java.util.Arrays;
23+
24+
25+
/**
26+
* Manages the request permission flow. {@link PermissionListener} can be used by clients who
27+
* wants to be notified about the permission status.
28+
*/
29+
30+
public class PermissionJavaHelper extends DialogFragment {
31+
32+
private static final String TAG = PermissionJavaHelper.class.getSimpleName();
33+
34+
private static final int PERMISSION_REQUEST_CODE = 100;
35+
36+
private static final String SAVE_INSTANCE_ALREADY_ASKED_KEY = "SAVE_INSTANCE_ALREADY_ASKED_KEY";
37+
38+
/**
39+
* Indicates the user has denied at least one permission, but not checked "Don't ask again".
40+
*/
41+
private boolean mShouldRetry;
42+
43+
/**
44+
* Indicates the user has denied at least one permission and checked "Don't ask again".
45+
*/
46+
private boolean mExternalRequestRequired;
47+
48+
/**
49+
* Indicates <code>onRequestPermissionsResult()</code> was called and we need to process the
50+
* current status in the <code>onResume()</code>.
51+
*/
52+
private boolean mCheckPermissionStatus;
53+
54+
/**
55+
* Flag to avoid recreate permissions dialog in cause orientation changes.
56+
*/
57+
private boolean mIsPermissionDialogShown;
58+
59+
/**
60+
* Called when user reject once or didn't check "Don't ask again" when reject a permission.
61+
*/
62+
private AlertDialog mRetryDialog;
63+
64+
/**
65+
* Called when user reject at least one permission and check "Don't ask again", so the user
66+
* is advised to goes to configuration of the application to allow the permission manually.
67+
*/
68+
private AlertDialog mAppSettingsDialog;
69+
70+
private Context mContext;
71+
72+
private String[] mRequestedPermissions;
73+
74+
private String mRetryTitle;
75+
76+
private String mRetryMessage;
77+
78+
private String mConfigurationTitle;
79+
80+
private String mConfigurationMessage;
81+
82+
private PermissionListener mListener;
83+
84+
public PermissionJavaHelper() {
85+
}
86+
87+
@Override
88+
public void onAttach(Context context) {
89+
super.onAttach(context);
90+
Log.d(TAG, "onAttach");
91+
mContext = context;
92+
if (context instanceof PermissionListener) {
93+
mListener = (PermissionListener) context;
94+
}
95+
}
96+
97+
@Override
98+
public void onCreate(@Nullable Bundle savedInstanceState) {
99+
super.onCreate(savedInstanceState);
100+
Log.d(TAG, "onCreate");
101+
102+
// Styling to make the background a little darker, like a dialog background.
103+
setStyle(STYLE_NO_TITLE, R.style.PermissionsDialogFragmentStyle);
104+
setCancelable(false);
105+
106+
mCheckPermissionStatus = false;
107+
mIsPermissionDialogShown = true;
108+
109+
// Check if must show permissions dialog if orientation changes and fragment is recreated.
110+
// If already showing, don't create again. If don't, create when user rotate the phone.
111+
if (savedInstanceState == null ||
112+
savedInstanceState.containsKey(SAVE_INSTANCE_ALREADY_ASKED_KEY) &&
113+
!savedInstanceState.getBoolean(SAVE_INSTANCE_ALREADY_ASKED_KEY)) {
114+
115+
116+
if (mRequestedPermissions != null && mRequestedPermissions.length != 0) {
117+
requestPermissions(mRequestedPermissions, PERMISSION_REQUEST_CODE);
118+
}
119+
}
120+
}
121+
122+
@Override
123+
public void onSaveInstanceState(Bundle outState) {
124+
super.onSaveInstanceState(outState);
125+
Log.d(TAG, "onSaveInstanceState");
126+
// Save if permission dialog is already displayed.
127+
outState.putBoolean(SAVE_INSTANCE_ALREADY_ASKED_KEY, mIsPermissionDialogShown);
128+
}
129+
130+
@Override
131+
public void onResume() {
132+
super.onResume();
133+
Log.d(TAG, "onResume - check permissions:" + mCheckPermissionStatus);
134+
135+
if (mCheckPermissionStatus) {
136+
if (areAllPermissionsGranted(mRequestedPermissions)) {
137+
Log.d(TAG, "all permissions granted");
138+
onPermissionGranted();
139+
} else {
140+
{
141+
Log.d(TAG,
142+
"not all permissions granted - retry:" + mShouldRetry
143+
+ "external request:"
144+
+ mExternalRequestRequired);
145+
}
146+
if (mExternalRequestRequired) {
147+
showAppSettingDialog();
148+
} else if (mShouldRetry) {
149+
showRetryDialog();
150+
}
151+
}
152+
}
153+
}
154+
155+
@Override
156+
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
157+
@NonNull int[] grantResults) {
158+
Log.d(TAG, "onRequestPermissionsResult");
159+
160+
mCheckPermissionStatus = true;
161+
mIsPermissionDialogShown = false;
162+
163+
for (int i = 0; i < permissions.length; i++) {
164+
final String permission = permissions[i];
165+
final int grantResult = grantResults[i];
166+
167+
if (!shouldShowRequestPermissionRationale(permission)
168+
&& grantResult != PackageManager.PERMISSION_GRANTED) {
169+
mExternalRequestRequired = true;
170+
return;
171+
} else if (grantResult != PackageManager.PERMISSION_GRANTED) {
172+
mShouldRetry = true;
173+
return;
174+
}
175+
}
176+
}
177+
178+
private void onPermissionGranted() {
179+
if (mListener != null) {
180+
mListener.onPermissionGranted();
181+
}
182+
dismiss();
183+
}
184+
185+
@Override
186+
public void onDetach() {
187+
super.onDetach();
188+
mContext = null;
189+
mListener = null;
190+
}
191+
192+
/**
193+
* Requests a single permission. If this is the first time user is facing the permission, a
194+
* dialog to confirm and reject will be shown. If the user already rejected once and
195+
* checked to
196+
* never be asked, the configuration screen is shown, so the user can toggle the
197+
* permissions by
198+
* itself.
199+
*
200+
* @param fragmentManager {@link FragmentManager} of the Activity that is calling.
201+
* @param permissions the permissions being requested.
202+
*/
203+
public void requestPermissions(@NonNull FragmentManager fragmentManager,
204+
@NonNull String[] permissions, String retryTitle, String retryMessage,
205+
String configurationTitle, String configurationMessage) {
206+
207+
Log.d(TAG, "requestPermissions");
208+
if (permissions.length == 0) {
209+
throw new IllegalArgumentException("Permissions array cannot be empty.");
210+
}
211+
212+
mRequestedPermissions = Arrays.copyOf(permissions, permissions.length);
213+
mRetryTitle = retryTitle;
214+
mRetryMessage = retryMessage;
215+
mConfigurationTitle = configurationTitle;
216+
mConfigurationMessage = configurationMessage;
217+
218+
final Fragment fragment = fragmentManager.findFragmentByTag(TAG);
219+
if (fragment == null && !isAdded()) {
220+
Log.d(TAG, "requestPermissions - show fragment");
221+
show(fragmentManager, TAG);
222+
fragmentManager.executePendingTransactions();
223+
}
224+
}
225+
226+
/**
227+
* Check if given permissions granted.
228+
*
229+
* @param permissions the {@link Manifest.permission}s to be checked.
230+
* @return <code>true</code> case ALL permission are granted, <code>false</code> otherwise.
231+
*/
232+
private boolean areAllPermissionsGranted(@NonNull String[] permissions) {
233+
Log.d(TAG, "areAllPermissionsGranted");
234+
if (permissions.length == 0) {
235+
throw new IllegalArgumentException("Permissions array cannot be empty.");
236+
}
237+
238+
for (String permission : permissions) {
239+
Log.d(TAG, "Checking permission: " + permission);
240+
if (ContextCompat.checkSelfPermission(mContext, permission)
241+
== PackageManager.PERMISSION_DENIED) {
242+
return false;
243+
}
244+
}
245+
return true;
246+
}
247+
248+
private void showAppSettingDialog() {
249+
Log.d(TAG, "showAppSettingDialog");
250+
if (mAppSettingsDialog != null && mAppSettingsDialog.isShowing()) {
251+
return;
252+
}
253+
254+
final AlertDialog.Builder builder = new AlertDialog
255+
.Builder(getContext())
256+
.setTitle(mConfigurationTitle)
257+
.setMessage(mConfigurationMessage)
258+
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
259+
@Override
260+
public void onClick(DialogInterface dialogInterface, int i) {
261+
showAppSettings();
262+
}
263+
})
264+
.setNegativeButton(android.R.string.cancel,
265+
new DialogInterface.OnClickListener() {
266+
@Override
267+
public void onClick(DialogInterface dialogInterface, int i) {
268+
onDialogPermissionCanceled();
269+
}
270+
})
271+
.setCancelable(false);
272+
273+
mAppSettingsDialog = builder.create();
274+
mAppSettingsDialog.show();
275+
}
276+
277+
private void showRetryDialog() {
278+
Log.d(TAG, "showRetryDialog");
279+
if (mRetryDialog != null && mRetryDialog.isShowing()) {
280+
return;
281+
}
282+
283+
final AlertDialog.Builder builder = new AlertDialog
284+
.Builder(getActivity())
285+
.setTitle(mRetryTitle)
286+
.setMessage(mRetryMessage)
287+
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
288+
@Override
289+
public void onClick(DialogInterface dialogInterface, int i) {
290+
requestPermissions(mRequestedPermissions, PERMISSION_REQUEST_CODE);
291+
}
292+
})
293+
.setNegativeButton(android.R.string.cancel,
294+
new DialogInterface.OnClickListener() {
295+
@Override
296+
public void onClick(DialogInterface dialogInterface, int i) {
297+
onDialogPermissionCanceled();
298+
}
299+
})
300+
.setCancelable(false);
301+
302+
mRetryDialog = builder.create();
303+
mRetryDialog.show();
304+
}
305+
306+
private void onDialogPermissionCanceled() {
307+
Log.d(TAG, "onDialogPermissionCanceled");
308+
309+
if (mListener != null) {
310+
mListener.onPermissionDenied();
311+
}
312+
dismiss();
313+
}
314+
315+
private void showAppSettings() {
316+
Log.d(TAG, "showAppSettings");
317+
final Intent intent = new Intent();
318+
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
319+
final Uri uri = Uri.fromParts("package", getContext().getPackageName(), null);
320+
intent.setData(uri);
321+
getContext().startActivity(intent);
322+
dismiss();
323+
}
324+
325+
/**
326+
* Callback interfaces for clients using this helper fragment.
327+
*/
328+
public interface PermissionListener {
329+
330+
/**
331+
* Called when all (and only all) permission are accepted.
332+
*/
333+
void onPermissionGranted();
334+
335+
/**
336+
* Called when at least one permission are denied.
337+
*/
338+
void onPermissionDenied();
339+
}
340+
}

app/src/main/java/com/orafaaraujo/androiddevconference2017/ui/MainNewWayActivity.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package com.orafaaraujo.androiddevconference2017.ui
22

3+
import android.Manifest
34
import android.os.Bundle
45
import android.support.v7.app.AppCompatActivity
56

67
import com.orafaaraujo.androiddevconference2017.R
78
import com.orafaaraujo.androiddevconference2017.helper.PermissionHelper
9+
import com.orafaaraujo.androiddevconference2017.helper.PermissionJavaHelper
810

911
/**
1012
* Created by rafael on 7/22/17.
@@ -16,11 +18,15 @@ class MainNewWayActivity : AppCompatActivity(), PermissionHelper.PermissionListe
1618
super.onCreate(savedInstanceState)
1719
setContentView(R.layout.activity_main)
1820

19-
val helper: PermissionHelper = PermissionHelper()
21+
val helper: PermissionJavaHelper = PermissionJavaHelper()
2022

2123
findViewById(R.id.activity_main_camera_title).
2224
setOnClickListener {
23-
helper.requestPermissionIfNeeded(supportFragmentManager)
25+
helper.requestPermissions(
26+
supportFragmentManager,
27+
arrayOf(Manifest.permission.CAMERA),
28+
"retry", "retryyyy",
29+
"config", "configggg")
2430
}
2531
}
2632

0 commit comments

Comments
 (0)