Compatibility.java

  1package eu.siacs.conversations.utils;
  2
  3import static eu.siacs.conversations.receiver.SystemEventReceiver.EXTRA_NEEDS_FOREGROUND_SERVICE;
  4
  5import android.annotation.SuppressLint;
  6import android.app.ActivityOptions;
  7import android.content.Context;
  8import android.content.Intent;
  9import android.content.SharedPreferences;
 10import android.content.pm.ApplicationInfo;
 11import android.content.pm.PackageManager;
 12import android.net.ConnectivityManager;
 13import android.os.Build;
 14import android.os.Bundle;
 15import android.preference.PreferenceManager;
 16import android.util.Log;
 17
 18import androidx.annotation.BoolRes;
 19import androidx.annotation.NonNull;
 20import androidx.annotation.RequiresApi;
 21import androidx.core.content.ContextCompat;
 22
 23import eu.siacs.conversations.AppSettings;
 24import eu.siacs.conversations.Config;
 25import eu.siacs.conversations.R;
 26
 27public class Compatibility {
 28
 29    public static boolean hasStoragePermission(final Context context) {
 30        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU || ContextCompat.checkSelfPermission(
 31                context, android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
 32    }
 33
 34    public static boolean s() {
 35        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
 36    }
 37
 38    private static boolean runsTwentyFour() {
 39        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;
 40    }
 41
 42    public static boolean runsTwentySix() {
 43        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O;
 44    }
 45
 46    public static boolean twentyEight() {
 47        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
 48    }
 49
 50    private static boolean getBooleanPreference(Context context, String name, @BoolRes int res) {
 51        return getPreferences(context).getBoolean(name, context.getResources().getBoolean(res));
 52    }
 53
 54    private static SharedPreferences getPreferences(final Context context) {
 55        return PreferenceManager.getDefaultSharedPreferences(context);
 56    }
 57
 58    private static boolean targetsTwentySix(Context context) {
 59        try {
 60            final PackageManager packageManager = context.getPackageManager();
 61            final ApplicationInfo applicationInfo =
 62                    packageManager.getApplicationInfo(context.getPackageName(), 0);
 63            return applicationInfo.targetSdkVersion >= 26;
 64        } catch (PackageManager.NameNotFoundException | RuntimeException e) {
 65            return true; // when in doubt…
 66        }
 67    }
 68
 69    private static boolean targetsTwentyFour(Context context) {
 70        try {
 71            final PackageManager packageManager = context.getPackageManager();
 72            final ApplicationInfo applicationInfo =
 73                    packageManager.getApplicationInfo(context.getPackageName(), 0);
 74            return applicationInfo.targetSdkVersion >= 24;
 75        } catch (PackageManager.NameNotFoundException | RuntimeException e) {
 76            return true; // when in doubt…
 77        }
 78    }
 79
 80    public static boolean runsAndTargetsTwentySix(Context context) {
 81        return runsTwentySix() && targetsTwentySix(context);
 82    }
 83
 84    public static boolean runsAndTargetsTwentyFour(Context context) {
 85        return runsTwentyFour() && targetsTwentyFour(context);
 86    }
 87
 88    public static boolean keepForegroundService(Context context) {
 89        return runsAndTargetsTwentySix(context)
 90                || getBooleanPreference(
 91                        context,
 92                        AppSettings.KEEP_FOREGROUND_SERVICE,
 93                        R.bool.enable_foreground_service);
 94    }
 95
 96
 97    public static void startService(final Context context, final Intent intent) {
 98        try {
 99            if (Compatibility.runsAndTargetsTwentySix(context)) {
100                intent.putExtra(EXTRA_NEEDS_FOREGROUND_SERVICE, true);
101                ContextCompat.startForegroundService(context, intent);
102            } else {
103                context.startService(intent);
104            }
105        } catch (final RuntimeException e) {
106            Log.d(
107                    Config.LOGTAG,
108                    context.getClass().getSimpleName() + " was unable to start service");
109        }
110    }
111
112    @SuppressLint("UnsupportedChromeOsCameraSystemFeature")
113    public static boolean hasFeatureCamera(final Context context) {
114        final PackageManager packageManager = context.getPackageManager();
115        return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
116    }
117
118    @RequiresApi(api = Build.VERSION_CODES.N)
119    public static int getRestrictBackgroundStatus(
120            @NonNull final ConnectivityManager connectivityManager) {
121        try {
122            return connectivityManager.getRestrictBackgroundStatus();
123        } catch (final Exception e) {
124            Log.d(
125                    Config.LOGTAG,
126                    "platform bug detected. Unable to get restrict background status",
127                    e);
128            return ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
129        }
130    }
131
132    @RequiresApi(api = Build.VERSION_CODES.N)
133    public static boolean isActiveNetworkMetered(
134            @NonNull final ConnectivityManager connectivityManager) {
135        try {
136            return connectivityManager.isActiveNetworkMetered();
137        } catch (final RuntimeException e) {
138            // when in doubt better assume it's metered
139            return true;
140        }
141    }
142
143    public static Bundle pgpStartIntentSenderOptions() {
144        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
145            return ActivityOptions.makeBasic()
146                    .setPendingIntentBackgroundActivityStartMode(
147                            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
148                    .toBundle();
149        } else {
150            return null;
151        }
152    }
153}