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