That fuck shit the fascists are using
1package org.tm.archive.util;
2
3import android.annotation.SuppressLint;
4import android.content.ContentResolver;
5import android.content.Context;
6import android.media.Ringtone;
7import android.media.RingtoneManager;
8import android.net.Uri;
9import android.provider.Settings;
10
11import androidx.annotation.NonNull;
12import androidx.annotation.Nullable;
13
14import org.signal.core.util.logging.Log;
15
16import java.lang.reflect.InvocationTargetException;
17import java.lang.reflect.Method;
18
19/**
20 * Some custom ROMs and some Samsung Android 11 devices have quirks around accessing the default ringtone. This attempts to deal
21 * with them with progressively worse approaches.
22 */
23public final class RingtoneUtil {
24
25 private static final String TAG = Log.tag(RingtoneUtil.class);
26
27 private RingtoneUtil() {}
28
29 public static @Nullable Ringtone getRingtone(@NonNull Context context, @NonNull Uri uri) {
30 Ringtone tone;
31 try {
32 tone = RingtoneManager.getRingtone(context, uri);
33 } catch (SecurityException e) {
34 Log.w(TAG, "Unable to get default ringtone due to permission", e);
35 tone = RingtoneManager.getRingtone(context, RingtoneUtil.getActualDefaultRingtoneUri(context));
36 }
37 return tone;
38 }
39
40 public static @Nullable Uri getActualDefaultRingtoneUri(@NonNull Context context) {
41 Log.i(TAG, "Attempting to get default ringtone directly via normal way");
42 try {
43 return RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE);
44 } catch (SecurityException e) {
45 Log.w(TAG, "Failed to get ringtone with first fallback approach", e);
46 }
47
48 Log.i(TAG, "Attempting to get default ringtone directly via reflection");
49 String uriString = getStringForUser(context.getContentResolver(), getUserId(context));
50 Uri ringtoneUri = uriString != null ? Uri.parse(uriString) : null;
51
52 if (ringtoneUri != null && getUserIdFromAuthority(ringtoneUri.getAuthority(), getUserId(context)) == getUserId(context)) {
53 ringtoneUri = getUriWithoutUserId(ringtoneUri);
54 }
55
56 return ringtoneUri;
57 }
58
59 @SuppressWarnings("JavaReflectionMemberAccess")
60 @SuppressLint("DiscouragedPrivateApi")
61 private static @Nullable String getStringForUser(@NonNull ContentResolver resolver, int userHandle) {
62 try {
63 Method getStringForUser = Settings.System.class.getMethod("getStringForUser", ContentResolver.class, String.class, int.class);
64 return (String) getStringForUser.invoke(Settings.System.class, resolver, Settings.System.RINGTONE, userHandle);
65 } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
66 Log.w(TAG, "Unable to getStringForUser via reflection", e);
67 }
68 return null;
69 }
70
71 @SuppressWarnings("JavaReflectionMemberAccess")
72 @SuppressLint("DiscouragedPrivateApi")
73 private static int getUserId(@NonNull Context context) {
74 try {
75 Object userId = Context.class.getMethod("getUserId").invoke(context);
76 if (userId instanceof Integer) {
77 return (Integer) userId;
78 } else {
79 Log.w(TAG, "getUserId did not return an integer");
80 }
81 } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
82 Log.w(TAG, "Unable to getUserId via reflection", e);
83 }
84 return 0;
85 }
86
87 private static @Nullable Uri getUriWithoutUserId(@Nullable Uri uri) {
88 if (uri == null) {
89 return null;
90 }
91 Uri.Builder builder = uri.buildUpon();
92 builder.authority(getAuthorityWithoutUserId(uri.getAuthority()));
93 return builder.build();
94 }
95
96 private static @Nullable String getAuthorityWithoutUserId(@Nullable String auth) {
97 if (auth == null) {
98 return null;
99 }
100 int end = auth.lastIndexOf('@');
101 return auth.substring(end + 1);
102 }
103
104 private static int getUserIdFromAuthority(@Nullable String authority, int defaultUserId) {
105 if (authority == null) {
106 return defaultUserId;
107 }
108
109 int end = authority.lastIndexOf('@');
110 if (end == -1) {
111 return defaultUserId;
112 }
113
114 String userIdString = authority.substring(0, end);
115 try {
116 return Integer.parseInt(userIdString);
117 } catch (NumberFormatException e) {
118 return defaultUserId;
119 }
120 }
121}