That fuck shit the fascists are using
at master 401 lines 14 kB view raw
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}