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    public static void startService(final Context context, final Intent intent) {
 97        try {
 98            if (Compatibility.runsAndTargetsTwentySix(context)) {
 99                intent.putExtra(EXTRA_NEEDS_FOREGROUND_SERVICE, true);
100                context.startForegroundService(intent);
101            } else {
102                context.startService(intent);
103            }
104        } catch (final RuntimeException e) {
105            Log.d(
106                    Config.LOGTAG,
107                    context.getClass().getSimpleName() + " was unable to start service");
108        }
109    }
110
111    @SuppressLint("UnsupportedChromeOsCameraSystemFeature")
112    public static boolean hasFeatureCamera(final Context context) {
113        final PackageManager packageManager = context.getPackageManager();
114        return packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY);
115    }
116
117    @RequiresApi(api = Build.VERSION_CODES.N)
118    public static int getRestrictBackgroundStatus(
119            @NonNull final ConnectivityManager connectivityManager) {
120        try {
121            return connectivityManager.getRestrictBackgroundStatus();
122        } catch (final Exception e) {
123            Log.d(
124                    Config.LOGTAG,
125                    "platform bug detected. Unable to get restrict background status",
126                    e);
127            return ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
128        }
129    }
130
131    @RequiresApi(api = Build.VERSION_CODES.N)
132    public static boolean isActiveNetworkMetered(
133            @NonNull final ConnectivityManager connectivityManager) {
134        try {
135            return connectivityManager.isActiveNetworkMetered();
136        } catch (final RuntimeException e) {
137            // when in doubt better assume it's metered
138            return true;
139        }
140    }
141
142    public static Bundle pgpStartIntentSenderOptions() {
143        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
144            return ActivityOptions.makeBasic()
145                    .setPendingIntentBackgroundActivityStartMode(
146                            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED)
147                    .toBundle();
148        } else {
149            return null;
150        }
151    }
152}