termux-app

Форк
0
573 строки · 27.6 Кб
1
package com.termux.shared.android;
2

3
import android.Manifest;
4
import android.annotation.SuppressLint;
5
import android.app.Activity;
6
import android.app.Service;
7
import android.content.Context;
8
import android.content.Intent;
9
import android.content.pm.PackageInfo;
10
import android.content.pm.PackageManager;
11
import android.net.Uri;
12
import android.os.Build;
13
import android.os.Environment;
14
import android.os.PowerManager;
15
import android.provider.Settings;
16

17
import androidx.annotation.NonNull;
18
import androidx.annotation.RequiresApi;
19
import androidx.appcompat.app.AppCompatActivity;
20
import androidx.core.content.ContextCompat;
21

22
import com.google.common.base.Joiner;
23
import com.termux.shared.R;
24
import com.termux.shared.file.FileUtils;
25
import com.termux.shared.logger.Logger;
26
import com.termux.shared.errors.Error;
27
import com.termux.shared.errors.FunctionErrno;
28
import com.termux.shared.activity.ActivityUtils;
29

30
import java.util.ArrayList;
31
import java.util.Arrays;
32
import java.util.Collections;
33
import java.util.List;
34

35
public class PermissionUtils {
36

37
    public static final int REQUEST_GRANT_STORAGE_PERMISSION = 1000;
38

39
    public static final int REQUEST_DISABLE_BATTERY_OPTIMIZATIONS = 2000;
40
    public static final int REQUEST_GRANT_DISPLAY_OVER_OTHER_APPS_PERMISSION = 2001;
41

42
    private static final String LOG_TAG = "PermissionUtils";
43

44

45
    /**
46
     * Check if app has been granted the required permission.
47
     *
48
     * @param context The context for operations.
49
     * @param permission The {@link String} name for permission to check.
50
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
51
     */
52
    public static boolean checkPermission(@NonNull Context context, @NonNull String permission) {
53
        return checkPermissions(context, new String[]{permission});
54
    }
55

56
    /**
57
     * Check if app has been granted the required permissions.
58
     *
59
     * @param context The context for operations.
60
     * @param permissions The {@link String[]} names for permissions to check.
61
     * @return Returns {@code true} if permissions are granted, otherwise {@code false}.
62
     */
63
    public static boolean checkPermissions(@NonNull Context context, @NonNull String[] permissions) {
64
        // checkSelfPermission may return true for permissions not even requested
65
        List<String> permissionsNotRequested = getPermissionsNotRequested(context, permissions);
66
        if (permissionsNotRequested.size() > 0) {
67
            Logger.logError(LOG_TAG,
68
                context.getString(R.string.error_attempted_to_check_for_permissions_not_requested,
69
                    Joiner.on(", ").join(permissionsNotRequested)));
70
            return false;
71
        }
72

73
        int result;
74
        for (String permission : permissions) {
75
            result = ContextCompat.checkSelfPermission(context, permission);
76
            if (result != PackageManager.PERMISSION_GRANTED) {
77
                return false;
78
            }
79
        }
80

81
        return true;
82
    }
83

84

85

86
    /**
87
     * Request user to grant required permissions to the app.
88
     *
89
     * @param context The context for operations. It must be an instance of {@link Activity} or
90
     * {@link AppCompatActivity}.
91
     * @param permission The {@link String} name for permission to request.
92
     * @param requestCode The request code to use while asking for permission. It must be `>=0` or
93
     *                    will fail silently and will log an exception.
94
     * @return Returns {@code true} if requesting the permission was successful, otherwise {@code false}.
95
     */
96
    @RequiresApi(api = Build.VERSION_CODES.M)
97
    public static boolean requestPermission(@NonNull Context context, @NonNull String permission,
98
                                            int requestCode) {
99
        return requestPermissions(context, new String[]{permission}, requestCode);
100
    }
101

102
    /**
103
     * Request user to grant required permissions to the app.
104
     *
105
     * On sdk 30 (android 11), Activity.onRequestPermissionsResult() will pass
106
     * {@link PackageManager#PERMISSION_DENIED} (-1) without asking the user for the permission
107
     * if user previously denied the permission prompt. On sdk 29 (android 10),
108
     * Activity.onRequestPermissionsResult() will pass {@link PackageManager#PERMISSION_DENIED} (-1)
109
     * without asking the user for the permission if user previously selected "Deny & don't ask again"
110
     * option in prompt. The user will have to manually enable permission in app info in Android
111
     * settings. If user grants and then denies in settings, then next time prompt will shown.
112
     *
113
     * @param context The context for operations. It must be an instance of {@link Activity} or
114
     * {@link AppCompatActivity}.
115
     * @param permissions The {@link String[]} names for permissions to request.
116
     * @param requestCode The request code to use while asking for permissions. It must be `>=0` or
117
     *                    will fail silently and will log an exception.
118
     * @return Returns {@code true} if requesting the permissions was successful, otherwise {@code false}.
119
     */
120
    @RequiresApi(api = Build.VERSION_CODES.M)
121
    public static boolean requestPermissions(@NonNull Context context, @NonNull String[] permissions,
122
                                             int requestCode) {
123
        List<String> permissionsNotRequested = getPermissionsNotRequested(context, permissions);
124
        if (permissionsNotRequested.size() > 0) {
125
            Logger.logErrorAndShowToast(context, LOG_TAG,
126
                context.getString(R.string.error_attempted_to_ask_for_permissions_not_requested,
127
                    Joiner.on(", ").join(permissionsNotRequested)));
128
            return false;
129
        }
130

131
        for (String permission : permissions) {
132
            int result = ContextCompat.checkSelfPermission(context, permission);
133
            // If at least one permission not granted
134
            if (result != PackageManager.PERMISSION_GRANTED) {
135
                Logger.logInfo(LOG_TAG, "Requesting Permissions: " + Arrays.toString(permissions));
136

137
                try {
138
                    if (context instanceof AppCompatActivity)
139
                        ((AppCompatActivity) context).requestPermissions(permissions, requestCode);
140
                    else if (context instanceof Activity)
141
                        ((Activity) context).requestPermissions(permissions, requestCode);
142
                    else {
143
                        Error.logErrorAndShowToast(context, LOG_TAG,
144
                            FunctionErrno.ERRNO_PARAMETER_NOT_INSTANCE_OF.getError("context", "requestPermissions", "Activity or AppCompatActivity"));
145
                        return false;
146
                    }
147
                } catch (Exception e) {
148
                    String errmsg = context.getString(R.string.error_failed_to_request_permissions, requestCode, Arrays.toString(permissions));
149
                    Logger.logStackTraceWithMessage(LOG_TAG, errmsg, e);
150
                    Logger.showToast(context, errmsg + "\n" + e.getMessage(), true);
151
                    return false;
152
                }
153

154
                break;
155
            }
156
        }
157

158
        return true;
159
    }
160

161

162

163

164
    /**
165
     * Check if app has requested the required permission in the manifest.
166
     *
167
     * @param context The context for operations.
168
     * @param permission The {@link String} name for permission to check.
169
     * @return Returns {@code true} if permission has been requested, otherwise {@code false}.
170
     */
171
    public static boolean isPermissionRequested(@NonNull Context context, @NonNull String permission) {
172
        return getPermissionsNotRequested(context, new String[]{permission}).size() == 0;
173
    }
174

175
    /**
176
     * Check if app has requested the required permissions or not in the manifest.
177
     *
178
     * @param context The context for operations.
179
     * @param permissions The {@link String[]} names for permissions to check.
180
     * @return Returns {@link List<String>} of permissions that have not been requested. It will have
181
     * size 0 if all permissions have been requested.
182
     */
183
    @NonNull
184
    public static List<String> getPermissionsNotRequested(@NonNull Context context, @NonNull String[] permissions) {
185
        List<String> permissionsNotRequested = new ArrayList<>();
186
        Collections.addAll(permissionsNotRequested, permissions);
187

188
        PackageInfo packageInfo = PackageUtils.getPackageInfoForPackage(context, PackageManager.GET_PERMISSIONS);
189
        if (packageInfo == null) {
190
            return permissionsNotRequested;
191
        }
192

193
        // If no permissions are requested, then nothing to check
194
        if (packageInfo.requestedPermissions == null || packageInfo.requestedPermissions.length == 0)
195
            return permissionsNotRequested;
196

197
        List<String> requestedPermissionsList = Arrays.asList(packageInfo.requestedPermissions);
198
        for (String permission : permissions) {
199
            if (requestedPermissionsList.contains(permission)) {
200
                permissionsNotRequested.remove(permission);
201
            }
202
        }
203

204
        return permissionsNotRequested;
205
    }
206

207

208

209

210
    /** If path is under primary external storage directory and storage permission is missing,
211
     * then legacy or manage external storage permission will be requested from the user via a call
212
     * to {@link #checkAndRequestLegacyOrManageExternalStoragePermission(Context, int, boolean)}.
213
     *
214
     * @param context The context for operations.
215
     * @param filePath The path to check.
216
     * @param requestCode The request code to use while asking for permission.
217
     * @param showErrorMessage If an error message toast should be shown if permission is not granted.
218
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
219
     */
220
    @SuppressLint("SdCardPath")
221
    public static boolean checkAndRequestLegacyOrManageExternalStoragePermissionIfPathOnPrimaryExternalStorage(
222
        @NonNull Context context, String filePath, int requestCode, boolean showErrorMessage) {
223
        // If path is under primary external storage directory, then check for missing permissions.
224
        if (!FileUtils.isPathInDirPaths(filePath,
225
            Arrays.asList(Environment.getExternalStorageDirectory().getAbsolutePath(), "/sdcard"), true))
226
            return true;
227

228
        return checkAndRequestLegacyOrManageExternalStoragePermission(context, requestCode, showErrorMessage);
229
    }
230

231
    /**
232
     * Check if legacy or manage external storage permissions has been granted. If
233
     * {@link #isLegacyExternalStoragePossible(Context)} returns {@code true}, them it will be
234
     * checked if app has has been granted {@link Manifest.permission#READ_EXTERNAL_STORAGE} and
235
     * {@link Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions, otherwise it will be checked
236
     * if app has been granted the {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission.
237
     *
238
     * If storage permission is missing, it will be requested from the user if {@code context} is an
239
     * instance of {@link Activity} or {@link AppCompatActivity} and {@code requestCode}
240
     * is `>=0` and the function will automatically return. The caller should register for
241
     * Activity.onActivityResult() and Activity.onRequestPermissionsResult() and call this function
242
     * again but set {@code requestCode} to `-1` to check if permission was granted or not.
243
     *
244
     * Caller must add following to AndroidManifest.xml of the app, otherwise errors will be thrown.
245
     * {@code
246
     * <manifest
247
     *     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
248
     *     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
249
     *     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage" />
250
     *
251
     *    <application
252
     *        android:requestLegacyExternalStorage="true"
253
     *        ....
254
     *    </application>
255
     * </manifest>
256
     *}
257
     * @param context The context for operations.
258
     * @param requestCode The request code to use while asking for permission.
259
     * @param showErrorMessage If an error message toast should be shown if permission is not granted.
260
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
261
     */
262
    public static boolean checkAndRequestLegacyOrManageExternalStoragePermission(@NonNull Context context,
263
                                                                                 int requestCode,
264
                                                                                 boolean showErrorMessage) {
265
        String errmsg;
266
        boolean requestLegacyStoragePermission = isLegacyExternalStoragePossible(context);
267
        boolean checkIfHasRequestedLegacyExternalStorage = checkIfHasRequestedLegacyExternalStorage(context);
268

269
        if (requestLegacyStoragePermission && checkIfHasRequestedLegacyExternalStorage) {
270
            // Check if requestLegacyExternalStorage is set to true in app manifest
271
            if (!hasRequestedLegacyExternalStorage(context, showErrorMessage))
272
                return false;
273
        }
274

275
        if (checkStoragePermission(context, requestLegacyStoragePermission)) {
276
            return true;
277
        }
278

279

280
        errmsg = context.getString(R.string.msg_storage_permission_not_granted);
281
        Logger.logError(LOG_TAG, errmsg);
282
        if (showErrorMessage)
283
            Logger.showToast(context, errmsg, false);
284

285
        if (requestCode < 0 || Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
286
            return false;
287

288
        if (requestLegacyStoragePermission || Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
289
            requestLegacyStorageExternalPermission(context, requestCode);
290
        } else {
291
            requestManageStorageExternalPermission(context, requestCode);
292
        }
293

294
        return false;
295
    }
296

297
    /**
298
     * Check if app has been granted storage permission.
299
     *
300
     * @param context The context for operations.
301
     * @param checkLegacyStoragePermission If set to {@code true}, then it will be checked if app
302
     *                                     has been granted {@link Manifest.permission#READ_EXTERNAL_STORAGE}
303
     *                                     and {@link Manifest.permission#WRITE_EXTERNAL_STORAGE}
304
     *                                     permissions, otherwise it will be checked if app has been
305
     *                                     granted the {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE}
306
     *                                     permission.
307
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
308
     */
309
    public static boolean checkStoragePermission(@NonNull Context context, boolean checkLegacyStoragePermission) {
310
        if (checkLegacyStoragePermission || Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
311
            return checkPermissions(context,
312
                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
313
                    Manifest.permission.WRITE_EXTERNAL_STORAGE});
314
        } else {
315
            return Environment.isExternalStorageManager();
316
        }
317
    }
318

319
    /**
320
     * Request user to grant {@link Manifest.permission#READ_EXTERNAL_STORAGE} and
321
     * {@link Manifest.permission#WRITE_EXTERNAL_STORAGE} permissions to the app.
322
     *
323
     * @param context The context for operations. It must be an instance of {@link Activity} or
324
     * {@link AppCompatActivity}.
325
     * @param requestCode The request code to use while asking for permission. It must be `>=0` or
326
     *                    will fail silently and will log an exception.
327
     * @return Returns {@code true} if requesting the permission was successful, otherwise {@code false}.
328
     */
329
    @RequiresApi(api = Build.VERSION_CODES.M)
330
    public static boolean requestLegacyStorageExternalPermission(@NonNull Context context, int requestCode) {
331
        Logger.logInfo(LOG_TAG, "Requesting legacy external storage permission");
332
        return requestPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE, requestCode);
333
    }
334

335
    /** Wrapper for {@link #requestManageStorageExternalPermission(Context, int)}. */
336
    @RequiresApi(api = Build.VERSION_CODES.R)
337
    public static Error requestManageStorageExternalPermission(@NonNull Context context) {
338
        return requestManageStorageExternalPermission(context, -1);
339
    }
340

341
    /**
342
     * Request user to grant {@link Manifest.permission#MANAGE_EXTERNAL_STORAGE} permission to the app.
343
     *
344
     * @param context The context for operations, like an {@link Activity} or {@link Service} context.
345
     *                It must be an instance of {@link Activity} or {@link AppCompatActivity} if
346
     *                result is required via the Activity#onActivityResult() callback and
347
     *                {@code requestCode} is `>=0`.
348
     * @param requestCode The request code to use while asking for permission. It must be `>=0` if
349
     *                    result it required.
350
     * @return Returns the {@code error} if requesting the permission was not successful, otherwise {@code null}.
351
     */
352
    @RequiresApi(api = Build.VERSION_CODES.R)
353
    public static Error requestManageStorageExternalPermission(@NonNull Context context, int requestCode) {
354
        Logger.logInfo(LOG_TAG, "Requesting manage external storage permission");
355

356
        Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
357
        intent.addCategory("android.intent.category.DEFAULT");
358
        intent.setData(Uri.parse("package:" + context.getPackageName()));
359

360
        // Flag must not be passed for activity contexts, otherwise onActivityResult() will not be called with permission grant result.
361
        // Flag must be passed for non-activity contexts like services, otherwise "Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag" exception will be raised.
362
        if (!(context instanceof Activity))
363
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
364

365
        Error error;
366
        if (requestCode >=0)
367
            error = ActivityUtils.startActivityForResult(context, requestCode, intent, true, false);
368
        else
369
            error = ActivityUtils.startActivity(context, intent, true, false);
370

371
        // Use fallback if matching Activity did not exist for ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION.
372
        if (error != null) {
373
            intent = new Intent();
374
            intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
375
            if (requestCode >=0)
376
                return ActivityUtils.startActivityForResult(context, requestCode, intent);
377
            else
378
                return ActivityUtils.startActivity(context, intent);
379
        }
380

381
        return null;
382
    }
383

384
    /**
385
     * If app is targeting targetSdkVersion 30 (android 11) and running on sdk 30 (android 11) or
386
     * higher, then {@link android.R.attr#requestLegacyExternalStorage} attribute is ignored.
387
     * https://developer.android.com/training/data-storage/use-cases#opt-out-scoped-storage
388
     */
389
    public static boolean isLegacyExternalStoragePossible(@NonNull Context context) {
390
        return !(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&
391
            PackageUtils.getTargetSDKForPackage(context) >= Build.VERSION_CODES.R);
392
    }
393

394
    /**
395
     * Return whether it should be checked if app has set
396
     * {@link android.R.attr#requestLegacyExternalStorage} attribute to {@code true}, if storage
397
     * permissions are to be requested based on if {@link #isLegacyExternalStoragePossible(Context)}
398
     * return {@code true}.
399
     *
400
     * If app is targeting targetSdkVersion 30 (android 11), then legacy storage can only be
401
     * requested if running on sdk 29 (android 10).
402
     * If app is targeting targetSdkVersion 29 (android 10), then legacy storage can only be
403
     * requested if running on sdk 29 (android 10) and higher.
404
     */
405
    public static boolean checkIfHasRequestedLegacyExternalStorage(@NonNull Context context) {
406
        int targetSdkVersion = PackageUtils.getTargetSDKForPackage(context);
407

408
        if (targetSdkVersion >= Build.VERSION_CODES.R) {
409
            return Build.VERSION.SDK_INT == Build.VERSION_CODES.Q;
410
        } else if (targetSdkVersion == Build.VERSION_CODES.Q) {
411
            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
412
        } else {
413
            return false;
414
        }
415
    }
416

417
    /**
418
     * Call to {@link Environment#isExternalStorageLegacy()} will not return the actual value defined
419
     * in app manifest for {@link android.R.attr#requestLegacyExternalStorage} attribute,
420
     * since an app may inherit its legacy state based on when it was first installed, target sdk and
421
     * other factors. To provide consistent experience for all users regardless of current legacy
422
     * state on a specific device, we directly use the value defined in app` manifest.
423
     */
424
    public static boolean hasRequestedLegacyExternalStorage(@NonNull Context context,
425
                                                            boolean showErrorMessage) {
426
        String errmsg;
427
        Boolean hasRequestedLegacyExternalStorage = PackageUtils.hasRequestedLegacyExternalStorage(context);
428
        if (hasRequestedLegacyExternalStorage != null && !hasRequestedLegacyExternalStorage) {
429
            errmsg = context.getString(R.string.error_has_not_requested_legacy_external_storage,
430
                context.getPackageName(), PackageUtils.getTargetSDKForPackage(context), Build.VERSION.SDK_INT);
431
            Logger.logError(LOG_TAG, errmsg);
432
            if (showErrorMessage)
433
                Logger.showToast(context, errmsg, true);
434
            return false;
435
        }
436

437
        return true;
438
    }
439

440

441

442

443

444
    /**
445
     * Check if {@link Manifest.permission#SYSTEM_ALERT_WINDOW} permission has been granted.
446
     *
447
     * @param context The context for operations.
448
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
449
     */
450
    public static boolean checkDisplayOverOtherAppsPermission(@NonNull Context context) {
451
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M)
452
            return Settings.canDrawOverlays(context);
453
        else
454
            return true;
455
    }
456

457
    /** Wrapper for {@link #requestDisplayOverOtherAppsPermission(Context, int)}. */
458
    public static Error requestDisplayOverOtherAppsPermission(@NonNull Context context) {
459
        return requestDisplayOverOtherAppsPermission(context, -1);
460
    }
461

462
    /**
463
     * Request user to grant {@link Manifest.permission#SYSTEM_ALERT_WINDOW} permission to the app.
464
     *
465
     * @param context The context for operations, like an {@link Activity} or {@link Service} context.
466
     *                It must be an instance of {@link Activity} or {@link AppCompatActivity} if
467
     *                result is required via the Activity#onActivityResult() callback and
468
     *                {@code requestCode} is `>=0`.
469
     * @param requestCode The request code to use while asking for permission. It must be `>=0` if
470
     *                    result it required.
471
     * @return Returns the {@code error} if requesting the permission was not successful, otherwise {@code null}.
472
     */
473
    public static Error requestDisplayOverOtherAppsPermission(@NonNull Context context, int requestCode) {
474
        Logger.logInfo(LOG_TAG, "Requesting display over apps permission");
475

476
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
477
            return null;
478

479
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
480
        intent.setData(Uri.parse("package:" + context.getPackageName()));
481

482
        // Flag must not be passed for activity contexts, otherwise onActivityResult() will not be called with permission grant result.
483
        // Flag must be passed for non-activity contexts like services, otherwise "Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag" exception will be raised.
484
        if (!(context instanceof Activity))
485
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
486

487
        if (requestCode >=0)
488
            return ActivityUtils.startActivityForResult(context, requestCode, intent);
489
        else
490
            return ActivityUtils.startActivity(context, intent);
491
    }
492

493
    /**
494
     * Check if running on sdk 29 (android 10) or higher and {@link Manifest.permission#SYSTEM_ALERT_WINDOW}
495
     * permission has been granted or not.
496
     *
497
     * @param context The context for operations.
498
     * @param logResults If it should be logged that permission has been granted or not.
499
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
500
     */
501
    public static boolean validateDisplayOverOtherAppsPermissionForPostAndroid10(@NonNull Context context,
502
                                                                                 boolean logResults) {
503
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return true;
504

505
        if (!checkDisplayOverOtherAppsPermission(context)) {
506
            if (logResults)
507
                Logger.logWarn(LOG_TAG, context.getPackageName() + " does not have Display over other apps (SYSTEM_ALERT_WINDOW) permission");
508
            return false;
509
        } else {
510
            if (logResults)
511
                Logger.logDebug(LOG_TAG, context.getPackageName() + " already has Display over other apps (SYSTEM_ALERT_WINDOW) permission");
512
            return true;
513
        }
514
    }
515

516

517

518

519

520
    /**
521
     * Check if {@link Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS} permission has been
522
     * granted.
523
     *
524
     * @param context The context for operations.
525
     * @return Returns {@code true} if permission is granted, otherwise {@code false}.
526
     */
527
    public static boolean checkIfBatteryOptimizationsDisabled(@NonNull Context context) {
528
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
529
            PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
530
            return powerManager.isIgnoringBatteryOptimizations(context.getPackageName());
531
        } else
532
            return true;
533
    }
534

535
    /** Wrapper for {@link #requestDisableBatteryOptimizations(Context, int)}. */
536
    public static Error requestDisableBatteryOptimizations(@NonNull Context context) {
537
        return requestDisableBatteryOptimizations(context, -1);
538
    }
539

540
    /**
541
     * Request user to grant {@link Manifest.permission#REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}
542
     * permission to the app.
543
     *
544
     * @param context The context for operations, like an {@link Activity} or {@link Service} context.
545
     *                It must be an instance of {@link Activity} or {@link AppCompatActivity} if
546
     *                result is required via the Activity#onActivityResult() callback and
547
     *                {@code requestCode} is `>=0`.
548
     * @param requestCode The request code to use while asking for permission. It must be `>=0` if
549
     *                    result it required.
550
     * @return Returns the {@code error} if requesting the permission was not successful, otherwise {@code null}.
551
     */
552
    @SuppressLint("BatteryLife")
553
    public static Error requestDisableBatteryOptimizations(@NonNull Context context, int requestCode) {
554
        Logger.logInfo(LOG_TAG, "Requesting to disable battery optimizations");
555

556
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
557
            return null;
558

559
        Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
560
        intent.setData(Uri.parse("package:" + context.getPackageName()));
561

562
        // Flag must not be passed for activity contexts, otherwise onActivityResult() will not be called with permission grant result.
563
        // Flag must be passed for non-activity contexts like services, otherwise "Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag" exception will be raised.
564
        if (!(context instanceof Activity))
565
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
566

567
        if (requestCode >=0)
568
            return ActivityUtils.startActivityForResult(context, requestCode, intent);
569
        else
570
            return ActivityUtils.startActivity(context, intent);
571
    }
572

573
}
574

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.