Skip to content

Commit 63f21be

Browse files
authored
Merge branch 'main' into dependabot/github_actions/gradle/actions-4.4.1
2 parents 62583a9 + 078e7fc commit 63f21be

File tree

34 files changed

+764
-90
lines changed

34 files changed

+764
-90
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
.DS_Store
22
.idea/
33
.gradle/
4+
.run/
45
build/
56
artifacts/
67
out/

CHANGELOG.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
# Changelog
22

3-
## Unreleased
3+
## 8.14.0
4+
5+
### Fixes
6+
7+
- Fix Session Replay masking for newer versions of Jetpack Compose (1.8+) ([#4485](https://github.com/getsentry/sentry-java/pull/4485))
48

59
### Features
610

11+
- Add New User Feedback Widget ([#4450](https://github.com/getsentry/sentry-java/pull/4450))
12+
- This widget is a custom button that can be used to show the user feedback form
713
- Add New User Feedback form ([#4384](https://github.com/getsentry/sentry-java/pull/4384))
814
- We now introduce SentryUserFeedbackDialog, which extends AlertDialog, inheriting the show() and cancel() methods, among others.
915
To use it, just instantiate it and call show() on the instance (Sentry must be previously initialized).
@@ -18,6 +24,14 @@
1824

1925
SentryUserFeedbackDialog.Builder(context).create().show()
2026
```
27+
- Add `user.id`, `user.name` and `user.email` to log attributes ([#4486](https://github.com/getsentry/sentry-java/pull/4486))
28+
- User `name` attribute has been deprecated, please use `username` instead ([#4486](https://github.com/getsentry/sentry-java/pull/4486))
29+
- Add device (`device.brand`, `device.model` and `device.family`) and OS (`os.name` and `os.version`) attributes to logs ([#4493](https://github.com/getsentry/sentry-java/pull/4493))
30+
- Serialize `preContext` and `postContext` in `SentryStackFrame` ([#4482](https://github.com/getsentry/sentry-java/pull/4482))
31+
32+
### Internal
33+
34+
- User Feedback now uses SentryUser.username instead of SentryUser.name ([#4494](https://github.com/getsentry/sentry-java/pull/4494))
2135

2236
## 8.13.3
2337

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ org.gradle.workers.max=2
1414
android.useAndroidX=true
1515

1616
# Release information
17-
versionName=8.13.3
17+
versionName=8.14.0
1818

1919
# Override the SDK name on native crashes on Android
2020
sentryAndroidSdkName=sentry.native.android

sentry-android-core/api/sentry-android-core.api

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,14 @@ public final class io/sentry/android/core/SentryPerformanceProvider {
385385
public fun shutdown ()V
386386
}
387387

388+
public class io/sentry/android/core/SentryUserFeedbackButton : android/widget/Button {
389+
public fun <init> (Landroid/content/Context;)V
390+
public fun <init> (Landroid/content/Context;Landroid/util/AttributeSet;)V
391+
public fun <init> (Landroid/content/Context;Landroid/util/AttributeSet;I)V
392+
public fun <init> (Landroid/content/Context;Landroid/util/AttributeSet;II)V
393+
public fun setOnClickListener (Landroid/view/View$OnClickListener;)V
394+
}
395+
388396
public final class io/sentry/android/core/SentryUserFeedbackDialog : android/app/AlertDialog {
389397
public fun setCancelable (Z)V
390398
public fun setOnDismissListener (Landroid/content/DialogInterface$OnDismissListener;)V

sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
import android.content.Context;
44
import android.content.pm.PackageInfo;
55
import android.content.pm.PackageManager;
6+
import android.os.Build;
67
import io.sentry.DateUtils;
78
import io.sentry.EventProcessor;
89
import io.sentry.Hint;
910
import io.sentry.IpAddressUtils;
11+
import io.sentry.NoOpLogger;
12+
import io.sentry.SentryAttributeType;
1013
import io.sentry.SentryBaseEvent;
1114
import io.sentry.SentryEvent;
1215
import io.sentry.SentryLevel;
16+
import io.sentry.SentryLogEvent;
17+
import io.sentry.SentryLogEventAttributeValue;
1318
import io.sentry.SentryReplayEvent;
1419
import io.sentry.android.core.internal.util.AndroidThreadChecker;
1520
import io.sentry.android.core.performance.AppStartMetrics;
@@ -23,6 +28,7 @@
2328
import io.sentry.protocol.SentryTransaction;
2429
import io.sentry.protocol.User;
2530
import io.sentry.util.HintUtils;
31+
import io.sentry.util.LazyEvaluator;
2632
import io.sentry.util.Objects;
2733
import java.util.Collections;
2834
import java.util.List;
@@ -42,6 +48,8 @@ final class DefaultAndroidEventProcessor implements EventProcessor {
4248
private final @NotNull BuildInfoProvider buildInfoProvider;
4349
private final @NotNull SentryAndroidOptions options;
4450
private final @NotNull Future<DeviceInfoUtil> deviceInfoUtil;
51+
private final @NotNull LazyEvaluator<String> deviceFamily =
52+
new LazyEvaluator<>(() -> ContextUtils.getFamily(NoOpLogger.getInstance()));
4553

4654
public DefaultAndroidEventProcessor(
4755
final @NotNull Context context,
@@ -81,6 +89,13 @@ public DefaultAndroidEventProcessor(
8189
return event;
8290
}
8391

92+
@Override
93+
public @Nullable SentryLogEvent process(@NotNull SentryLogEvent event) {
94+
setDevice(event);
95+
setOs(event);
96+
return event;
97+
}
98+
8499
/**
85100
* The last exception is usually used for picking the issue title, but the convention is to send
86101
* inner exceptions first, e.g. [inner, outer] This doesn't work very well on Android, as some
@@ -199,6 +214,34 @@ private void mergeOS(final @NotNull SentryBaseEvent event) {
199214
}
200215
}
201216

217+
private void setDevice(final @NotNull SentryLogEvent event) {
218+
try {
219+
event.setAttribute(
220+
"device.brand",
221+
new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.BRAND));
222+
event.setAttribute(
223+
"device.model",
224+
new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.MODEL));
225+
event.setAttribute(
226+
"device.family",
227+
new SentryLogEventAttributeValue(SentryAttributeType.STRING, deviceFamily.getValue()));
228+
} catch (Throwable e) {
229+
options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve device info", e);
230+
}
231+
}
232+
233+
private void setOs(final @NotNull SentryLogEvent event) {
234+
try {
235+
event.setAttribute(
236+
"os.name", new SentryLogEventAttributeValue(SentryAttributeType.STRING, "Android"));
237+
event.setAttribute(
238+
"os.version",
239+
new SentryLogEventAttributeValue(SentryAttributeType.STRING, Build.VERSION.RELEASE));
240+
} catch (Throwable e) {
241+
options.getLogger().log(SentryLevel.ERROR, "Failed to retrieve os system", e);
242+
}
243+
}
244+
202245
// Data to be applied to events that was created in the running process
203246
private void processNonCachedEvent(
204247
final @NotNull SentryBaseEvent event, final @NotNull Hint hint) {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package io.sentry.android.core;
2+
3+
import android.annotation.SuppressLint;
4+
import android.content.Context;
5+
import android.content.res.TypedArray;
6+
import android.os.Build;
7+
import android.util.AttributeSet;
8+
import android.util.TypedValue;
9+
import android.widget.Button;
10+
import org.jetbrains.annotations.NotNull;
11+
import org.jetbrains.annotations.Nullable;
12+
13+
public class SentryUserFeedbackButton extends Button {
14+
15+
private @Nullable OnClickListener delegate;
16+
17+
public SentryUserFeedbackButton(Context context) {
18+
super(context);
19+
init(context, null, 0, 0);
20+
}
21+
22+
public SentryUserFeedbackButton(Context context, AttributeSet attrs) {
23+
super(context, attrs);
24+
init(context, attrs, 0, 0);
25+
}
26+
27+
public SentryUserFeedbackButton(Context context, AttributeSet attrs, int defStyleAttr) {
28+
super(context, attrs, defStyleAttr);
29+
init(context, attrs, defStyleAttr, 0);
30+
}
31+
32+
public SentryUserFeedbackButton(
33+
Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
34+
super(context, attrs, defStyleAttr, defStyleRes);
35+
init(context, attrs, defStyleAttr, defStyleRes);
36+
}
37+
38+
@SuppressLint("SetTextI18n")
39+
@SuppressWarnings("deprecation")
40+
private void init(
41+
final @NotNull Context context,
42+
final @Nullable AttributeSet attrs,
43+
final int defStyleAttr,
44+
final int defStyleRes) {
45+
try (final @NotNull TypedArray typedArray =
46+
context.obtainStyledAttributes(
47+
attrs, R.styleable.SentryUserFeedbackButton, defStyleAttr, defStyleRes)) {
48+
final float dimensionScale = context.getResources().getDisplayMetrics().density;
49+
final float drawablePadding =
50+
typedArray.getDimension(R.styleable.SentryUserFeedbackButton_android_drawablePadding, -1);
51+
final int drawableStart =
52+
typedArray.getResourceId(R.styleable.SentryUserFeedbackButton_android_drawableStart, -1);
53+
final boolean textAllCaps =
54+
typedArray.getBoolean(R.styleable.SentryUserFeedbackButton_android_textAllCaps, false);
55+
final int background =
56+
typedArray.getResourceId(R.styleable.SentryUserFeedbackButton_android_background, -1);
57+
final float padding =
58+
typedArray.getDimension(R.styleable.SentryUserFeedbackButton_android_padding, -1);
59+
final int textColor =
60+
typedArray.getColor(R.styleable.SentryUserFeedbackButton_android_textColor, -1);
61+
final @Nullable String text =
62+
typedArray.getString(R.styleable.SentryUserFeedbackButton_android_text);
63+
64+
// If the drawable padding is not set, set it to 4dp
65+
if (drawablePadding == -1) {
66+
setCompoundDrawablePadding((int) (4 * dimensionScale));
67+
}
68+
69+
// If the drawable start is not set, set it to the default drawable
70+
if (drawableStart == -1) {
71+
setCompoundDrawablesRelativeWithIntrinsicBounds(
72+
R.drawable.sentry_user_feedback_button_logo_24, 0, 0, 0);
73+
}
74+
75+
// Set the text all caps
76+
setAllCaps(textAllCaps);
77+
78+
// If the background is not set, set it to the default background
79+
if (background == -1) {
80+
setBackgroundResource(R.drawable.sentry_oval_button_ripple_background);
81+
}
82+
83+
// If the padding is not set, set it to 12dp
84+
if (padding == -1) {
85+
int defaultPadding = (int) (12 * dimensionScale);
86+
setPadding(defaultPadding, defaultPadding, defaultPadding, defaultPadding);
87+
}
88+
89+
// If the text color is not set, set it to the default text color
90+
if (textColor == -1) {
91+
// We need the TypedValue to resolve the color from the theme
92+
final @NotNull TypedValue typedValue = new TypedValue();
93+
context.getTheme().resolveAttribute(android.R.attr.colorForeground, typedValue, true);
94+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
95+
setTextColor(context.getResources().getColor(typedValue.resourceId, context.getTheme()));
96+
} else {
97+
setTextColor(context.getResources().getColor(typedValue.resourceId));
98+
}
99+
}
100+
101+
// If the text is not set, set it to "Report a Bug"
102+
if (text == null) {
103+
setText("Report a Bug");
104+
}
105+
}
106+
107+
// Set the default ClickListener to open the SentryUserFeedbackDialog
108+
setOnClickListener(delegate);
109+
}
110+
111+
@Override
112+
public void setOnClickListener(final @Nullable OnClickListener listener) {
113+
delegate = listener;
114+
super.setOnClickListener(
115+
v -> {
116+
new SentryUserFeedbackDialog.Builder(getContext()).create().show();
117+
if (delegate != null) {
118+
delegate.onClick(v);
119+
}
120+
});
121+
}
122+
}

sentry-android-core/src/main/java/io/sentry/android/core/SentryUserFeedbackDialog.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public void setCancelable(boolean cancelable) {
4343
}
4444

4545
@Override
46+
@SuppressWarnings("deprecation")
4647
protected void onCreate(Bundle savedInstanceState) {
4748
super.onCreate(savedInstanceState);
4849
setContentView(R.layout.sentry_dialog_user_feedback);
@@ -104,7 +105,7 @@ protected void onCreate(Bundle savedInstanceState) {
104105
if (feedbackOptions.isUseSentryUser()) {
105106
final @Nullable User user = Sentry.getCurrentScopes().getScope().getUser();
106107
if (user != null) {
107-
edtName.setText(user.getName());
108+
edtName.setText(user.getUsername());
108109
edtEmail.setText(user.getEmail());
109110
}
110111
}
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)