Compatibility.java

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