That fuck shit the fascists are using
1package org.tm.archive.permissions;
2
3
4import android.app.Activity;
5import android.content.Context;
6import android.content.Intent;
7import android.content.pm.PackageManager;
8import android.net.Uri;
9import android.os.Build;
10import android.provider.Settings;
11import android.util.DisplayMetrics;
12import android.view.Display;
13import android.view.ViewGroup;
14import android.view.WindowManager;
15
16import androidx.annotation.DrawableRes;
17import androidx.annotation.NonNull;
18import androidx.annotation.Nullable;
19import androidx.core.app.ActivityCompat;
20import androidx.core.content.ContextCompat;
21import androidx.fragment.app.Fragment;
22
23import com.annimon.stream.Stream;
24import com.annimon.stream.function.Consumer;
25import com.google.android.material.dialog.MaterialAlertDialogBuilder;
26
27import org.signal.core.util.logging.Log;
28import org.tm.archive.R;
29import org.tm.archive.util.LRUCache;
30import org.tm.archive.util.ServiceUtil;
31
32import java.lang.ref.WeakReference;
33import java.security.SecureRandom;
34import java.util.Arrays;
35import java.util.List;
36import java.util.Map;
37
38public class Permissions {
39
40 private static final String TAG = Log.tag(Permissions.class);
41
42 private static final Map<Integer, PermissionsRequest> OUTSTANDING = new LRUCache<>(2);
43
44 public static PermissionsBuilder with(@NonNull Activity activity) {
45 return new PermissionsBuilder(new ActivityPermissionObject(activity));
46 }
47
48 public static PermissionsBuilder with(@NonNull Fragment fragment) {
49 return new PermissionsBuilder(new FragmentPermissionObject(fragment));
50 }
51
52 public static boolean isRuntimePermissionsRequired() {
53 return Build.VERSION.SDK_INT >= 23;
54 }
55
56 public static class PermissionsBuilder {
57
58 private final PermissionObject permissionObject;
59
60 private String[] requestedPermissions;
61
62 private Runnable allGrantedListener;
63
64 private Runnable anyDeniedListener;
65 private Runnable anyPermanentlyDeniedListener;
66 private Runnable anyResultListener;
67
68 private Consumer<List<String>> someGrantedListener;
69 private Consumer<List<String>> someDeniedListener;
70 private Consumer<List<String>> somePermanentlyDeniedListener;
71
72 private @DrawableRes int[] rationalDialogHeader;
73 private String rationaleDialogMessage;
74 private boolean rationaleDialogCancelable;
75
76 private boolean ifNecesary;
77
78 private boolean condition = true;
79
80 PermissionsBuilder(PermissionObject permissionObject) {
81 this.permissionObject = permissionObject;
82 }
83
84 public PermissionsBuilder request(String... requestedPermissions) {
85 this.requestedPermissions = requestedPermissions;
86 return this;
87 }
88
89 public PermissionsBuilder ifNecessary() {
90 this.ifNecesary = true;
91 return this;
92 }
93
94 public PermissionsBuilder ifNecessary(boolean condition) {
95 this.ifNecesary = true;
96 this.condition = condition;
97 return this;
98 }
99
100 public PermissionsBuilder withRationaleDialog(@NonNull String message, @NonNull @DrawableRes int... headers) {
101 return withRationaleDialog(message, true, headers);
102 }
103
104 public PermissionsBuilder withRationaleDialog(@NonNull String message, boolean cancelable, @NonNull @DrawableRes int... headers) {
105 this.rationalDialogHeader = headers;
106 this.rationaleDialogMessage = message;
107 this.rationaleDialogCancelable = cancelable;
108 return this;
109 }
110
111 public PermissionsBuilder withPermanentDenialDialog(@NonNull String message) {
112 return withPermanentDenialDialog(message, null);
113 }
114
115 public PermissionsBuilder withPermanentDenialDialog(@NonNull String message, @Nullable Runnable onDialogDismissed) {
116 return onAnyPermanentlyDenied(new SettingsDialogListener(permissionObject.getContext(), message, onDialogDismissed));
117 }
118
119 public PermissionsBuilder onAllGranted(Runnable allGrantedListener) {
120 this.allGrantedListener = allGrantedListener;
121 return this;
122 }
123
124 public PermissionsBuilder onAnyDenied(Runnable anyDeniedListener) {
125 this.anyDeniedListener = anyDeniedListener;
126 return this;
127 }
128
129 @SuppressWarnings("WeakerAccess")
130 public PermissionsBuilder onAnyPermanentlyDenied(Runnable anyPermanentlyDeniedListener) {
131 this.anyPermanentlyDeniedListener = anyPermanentlyDeniedListener;
132 return this;
133 }
134
135 public PermissionsBuilder onAnyResult(Runnable anyResultListener) {
136 this.anyResultListener = anyResultListener;
137 return this;
138 }
139
140 public PermissionsBuilder onSomeGranted(Consumer<List<String>> someGrantedListener) {
141 this.someGrantedListener = someGrantedListener;
142 return this;
143 }
144
145 public PermissionsBuilder onSomeDenied(Consumer<List<String>> someDeniedListener) {
146 this.someDeniedListener = someDeniedListener;
147 return this;
148 }
149
150 public PermissionsBuilder onSomePermanentlyDenied(Consumer<List<String>> somePermanentlyDeniedListener) {
151 this.somePermanentlyDeniedListener = somePermanentlyDeniedListener;
152 return this;
153 }
154
155 public void execute() {
156 PermissionsRequest request = new PermissionsRequest(allGrantedListener, anyDeniedListener, anyPermanentlyDeniedListener, anyResultListener,
157 someGrantedListener, someDeniedListener, somePermanentlyDeniedListener);
158
159 if (ifNecesary && (permissionObject.hasAll(requestedPermissions) || !condition)) {
160 executePreGrantedPermissionsRequest(request);
161 } else if (rationaleDialogMessage != null && rationalDialogHeader != null) {
162 executePermissionsRequestWithRationale(request);
163 } else {
164 executePermissionsRequest(request);
165 }
166 }
167
168 private void executePreGrantedPermissionsRequest(PermissionsRequest request) {
169 int[] grantResults = new int[requestedPermissions.length];
170 for (int i=0;i<grantResults.length;i++) grantResults[i] = PackageManager.PERMISSION_GRANTED;
171
172 request.onResult(requestedPermissions, grantResults, new boolean[requestedPermissions.length]);
173 }
174
175 @SuppressWarnings("ConstantConditions")
176 private void executePermissionsRequestWithRationale(PermissionsRequest request) {
177 RationaleDialog.createFor(permissionObject.getContext(), rationaleDialogMessage, rationalDialogHeader)
178 .setPositiveButton(R.string.Permissions_continue, (dialog, which) -> executePermissionsRequest(request))
179 .setNegativeButton(R.string.Permissions_not_now, (dialog, which) -> executeNoPermissionsRequest(request))
180 .setCancelable(rationaleDialogCancelable)
181 .show()
182 .getWindow()
183 .setLayout((int)(permissionObject.getWindowWidth() * .75), ViewGroup.LayoutParams.WRAP_CONTENT);
184 }
185
186 private void executePermissionsRequest(PermissionsRequest request) {
187 int requestCode = new SecureRandom().nextInt(65434) + 100;
188
189 synchronized (OUTSTANDING) {
190 OUTSTANDING.put(requestCode, request);
191 }
192
193 for (String permission : requestedPermissions) {
194 request.addMapping(permission, permissionObject.shouldShouldPermissionRationale(permission));
195 }
196
197 permissionObject.requestPermissions(requestCode, requestedPermissions);
198 }
199
200 private void executeNoPermissionsRequest(PermissionsRequest request) {
201 for (String permission : requestedPermissions) {
202 request.addMapping(permission, true);
203 }
204
205 String[] permissions = filterNotGranted(permissionObject.getContext(), requestedPermissions);
206 int[] grantResults = Stream.of(permissions).mapToInt(permission -> PackageManager.PERMISSION_DENIED).toArray();
207 boolean[] showDialog = new boolean[permissions.length];
208 Arrays.fill(showDialog, true);
209
210 request.onResult(permissions, grantResults, showDialog);
211 }
212
213 }
214
215 private static void requestPermissions(@NonNull Activity activity, int requestCode, String... permissions) {
216 String[] neededPermissions = filterNotGranted(activity, permissions);
217
218 if (neededPermissions.length == 0) {
219 Log.i(TAG, "No permissions needed!");
220 return;
221 }
222
223 ActivityCompat.requestPermissions(activity, neededPermissions, requestCode);
224 }
225
226 private static void requestPermissions(@NonNull Fragment fragment, int requestCode, String... permissions) {
227 String[] neededPermissions = filterNotGranted(fragment.requireContext(), permissions);
228
229 if (neededPermissions.length == 0) {
230 Log.i(TAG, "No permissions needed!");
231 return;
232 }
233
234
235 fragment.requestPermissions(neededPermissions, requestCode);
236 }
237
238 private static String[] filterNotGranted(@NonNull Context context, String... permissions) {
239 return Stream.of(permissions)
240 .filter(permission -> ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED)
241 .toList()
242 .toArray(new String[0]);
243 }
244
245 public static boolean hasAny(@NonNull Context context, String... permissions) {
246 return !isRuntimePermissionsRequired() ||
247 Stream.of(permissions).anyMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
248
249 }
250
251 public static boolean hasAll(@NonNull Context context, String... permissions) {
252 return !isRuntimePermissionsRequired() ||
253 Stream.of(permissions).allMatch(permission -> ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED);
254
255 }
256
257 public static void onRequestPermissionsResult(Fragment fragment, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
258 onRequestPermissionsResult(new FragmentPermissionObject(fragment), requestCode, permissions, grantResults);
259 }
260
261 public static void onRequestPermissionsResult(Activity activity, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
262 onRequestPermissionsResult(new ActivityPermissionObject(activity), requestCode, permissions, grantResults);
263 }
264
265 private static void onRequestPermissionsResult(@NonNull PermissionObject context, int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
266 PermissionsRequest resultListener;
267
268 synchronized (OUTSTANDING) {
269 resultListener = OUTSTANDING.remove(requestCode);
270 }
271
272 if (resultListener == null) return;
273
274 boolean[] shouldShowRationaleDialog = new boolean[permissions.length];
275
276 for (int i=0;i<permissions.length;i++) {
277 if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
278 shouldShowRationaleDialog[i] = context.shouldShouldPermissionRationale(permissions[i]);
279 }
280 }
281
282 resultListener.onResult(permissions, grantResults, shouldShowRationaleDialog);
283 }
284
285 public static Intent getApplicationSettingsIntent(@NonNull Context context) {
286 Intent intent = new Intent();
287 intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
288 Uri uri = Uri.fromParts("package", context.getPackageName(), null);
289 intent.setData(uri);
290
291 return intent;
292 }
293
294 private abstract static class PermissionObject {
295
296 abstract Context getContext();
297 abstract boolean shouldShouldPermissionRationale(String permission);
298 abstract boolean hasAll(String... permissions);
299 abstract void requestPermissions(int requestCode, String... permissions);
300
301 int getWindowWidth() {
302 WindowManager windowManager = ServiceUtil.getWindowManager(getContext());
303 Display display = windowManager.getDefaultDisplay();
304 DisplayMetrics metrics = new DisplayMetrics();
305 display.getMetrics(metrics);
306
307 return metrics.widthPixels;
308 }
309 }
310
311 private static class ActivityPermissionObject extends PermissionObject {
312
313 private Activity activity;
314
315 ActivityPermissionObject(@NonNull Activity activity) {
316 this.activity = activity;
317 }
318
319 @Override
320 public Context getContext() {
321 return activity;
322 }
323
324 @Override
325 public boolean shouldShouldPermissionRationale(String permission) {
326 return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
327 }
328
329 @Override
330 public boolean hasAll(String... permissions) {
331 return Permissions.hasAll(activity, permissions);
332 }
333
334 @Override
335 public void requestPermissions(int requestCode, String... permissions) {
336 Permissions.requestPermissions(activity, requestCode, permissions);
337 }
338 }
339
340 private static class FragmentPermissionObject extends PermissionObject {
341
342 private Fragment fragment;
343
344 FragmentPermissionObject(@NonNull Fragment fragment) {
345 this.fragment = fragment;
346 }
347
348 @Override
349 public Context getContext() {
350 return fragment.getContext();
351 }
352
353 @Override
354 public boolean shouldShouldPermissionRationale(String permission) {
355 return fragment.shouldShowRequestPermissionRationale(permission);
356 }
357
358 @Override
359 public boolean hasAll(String... permissions) {
360 return Permissions.hasAll(fragment.getContext(), permissions);
361 }
362
363 @Override
364 public void requestPermissions(int requestCode, String... permissions) {
365 Permissions.requestPermissions(fragment, requestCode, permissions);
366 }
367 }
368
369 private static class SettingsDialogListener implements Runnable {
370
371 private final WeakReference<Context> context;
372 private final Runnable onDialogDismissed;
373 private final String message;
374
375 SettingsDialogListener(Context context, String message, @Nullable Runnable onDialogDismissed) {
376 this.message = message;
377 this.context = new WeakReference<>(context);
378 this.onDialogDismissed = onDialogDismissed;
379 }
380
381 @Override
382 public void run() {
383 Context context = this.context.get();
384
385 if (context != null) {
386 new MaterialAlertDialogBuilder(context)
387 .setTitle(R.string.Permissions_permission_required)
388 .setMessage(message)
389 .setCancelable(false)
390 .setPositiveButton(R.string.Permissions_continue, (dialog, which) -> context.startActivity(getApplicationSettingsIntent(context)))
391 .setNegativeButton(android.R.string.cancel, null)
392 .setOnDismissListener(d -> {
393 if (onDialogDismissed != null) {
394 onDialogDismissed.run();
395 }
396 })
397 .show();
398 }
399 }
400 }
401}