Skip to content

Commit 2bf5db2

Browse files
authored
[analytics] initial sendReport API (#8608)
A jumping off point for a `sendReport` implementation. Next step is to add params and do some experimenting w/ DTD. You'll note that this handles error conditions a little differently than the other DTD interactions and I'm open to feedback. (In those cases we return futures that will blow up if interrogated. I'm not sure we want to do that here (or even if we'll ever ask?)) Dunno. --- - [x] I’ve reviewed the contributor guide and applied the relevant portions to this PR. <details> <summary>Contribution guidelines:</summary><br> - See our [contributor guide]([https://github.com/dart-lang/sdk/blob/main/CONTRIBUTING.md](https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview) for general expectations for PRs. - Larger or significant changes should be discussed in an issue before creating a PR. - Dart contributions to our repos should follow the [Dart style guide](https://dart.dev/guides/language/effective-dart) and use `dart format`. - Java and Kotlin contributions should strive to follow Java and Kotlin best practices ([discussion](#8098)). </details>
1 parent 1730954 commit 2bf5db2

File tree

1 file changed

+85
-13
lines changed

1 file changed

+85
-13
lines changed

src/io/flutter/analytics/UnifiedAnalytics.java

Lines changed: 85 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,9 @@ public class UnifiedAnalytics {
3232
private static final @NotNull Logger LOG = PluginLogger.createLogger(UnifiedAnalytics.class);
3333

3434
@Nullable Boolean enabled = null;
35-
final Project project;
36-
final DtdUtils dtdUtils;
37-
@NotNull final FlutterSdkUtil flutterSdkUtil;
38-
35+
final @NotNull Project project;
36+
final @NotNull DtdUtils dtdUtils;
37+
final @NotNull FlutterSdkUtil flutterSdkUtil;
3938

4039
public UnifiedAnalytics(@NotNull Project project) {
4140
this.project = project;
@@ -71,6 +70,48 @@ public void manageConsent() {
7170
}
7271
}
7372

73+
/**
74+
* Sends analytics data to the unified analytics service.
75+
*
76+
* @param analyticsData The data object containing the details of the event to report.
77+
* @return A {@link CompletableFuture} that completes with a {@link SendResult}.
78+
* The {@code SendResult} will indicate whether the report was successfully
79+
* sent and may contain a message with additional details on failure.
80+
* If the analytics service is unavailable or an error occurs, the future
81+
* will complete with a result where {@code success} is false.
82+
*/
83+
public @NotNull CompletableFuture<SendResult> sendReport(AnalyticsData analyticsData) {
84+
try {
85+
DartToolingDaemonService service = dtdUtils.readyDtdService(project).get();
86+
if (service == null) {
87+
return SendResult.failed("DTD service is null");
88+
}
89+
90+
JsonObject params = new JsonObject();
91+
params.addProperty("tool", getToolName());
92+
93+
// TODO (pq): convert analyticsData to params.
94+
95+
// TODO (pq): hoist request constants into static fields
96+
return makeUnifiedAnalyticsRequest("ideEvent", service, params).thenCompose(result -> {
97+
if (result == null) {
98+
return SendResult.failed("ideEvent result is null");
99+
}
100+
101+
JsonPrimitive type = result.getAsJsonPrimitive("type");
102+
if (type == null) {
103+
return SendResult.failed("ideEvent result type is null");
104+
}
105+
106+
return SendResult.succeeded("Success".equals(type.getAsString()));
107+
});
108+
}
109+
catch (Exception e) {
110+
LOG.info(e);
111+
return SendResult.failed(e.getMessage());
112+
}
113+
}
114+
74115
private @NotNull CompletableFuture<JsonObject> makeUnifiedAnalyticsRequest(String requestName,
75116
@NotNull DartToolingDaemonService service,
76117
@NotNull JsonObject params) {
@@ -168,15 +209,11 @@ public void actionPerformed(@NotNull AnActionEvent event) {
168209

169210
private String getToolName() throws Exception {
170211
String ideValue = flutterSdkUtil.getFlutterHostEnvValue();
171-
if ("IntelliJ-IDEA".equals(ideValue)) {
172-
return "intellij-plugins";
173-
}
174-
else if ("Android-Studio".equals(ideValue)) {
175-
return "android-studio-plugins";
176-
}
177-
else {
178-
throw new Exception("Tool name cannot be found for IDE type: " + ideValue);
179-
}
212+
return switch (flutterSdkUtil.getFlutterHostEnvValue()) {
213+
case "IntelliJ-IDEA" -> "intellij-plugins";
214+
case "Android-Studio" -> "android-studio-plugins";
215+
default -> throw new Exception("Tool name cannot be found for IDE type: " + ideValue);
216+
};
180217
}
181218

182219
private @NotNull CompletableFuture<Boolean> shouldShowMessage(@NotNull DartToolingDaemonService service, @NotNull JsonObject params) {
@@ -206,3 +243,38 @@ else if ("Android-Studio".equals(ideValue)) {
206243
});
207244
}
208245
}
246+
247+
/**
248+
* Represents the result of an analytics sending operation.
249+
* <p>
250+
* This class encapsulates whether the operation was successful and includes an
251+
* optional message, typically used for logging errors.
252+
*/
253+
class SendResult {
254+
/**
255+
* True if the analytics report was sent successfully, false otherwise.
256+
*/
257+
public final boolean success;
258+
259+
/**
260+
* An optional message providing more details about the result, particularly on failure.
261+
*/
262+
public final @Nullable String message;
263+
264+
SendResult(boolean success, @Nullable String message) {
265+
this.success = success;
266+
this.message = message;
267+
}
268+
269+
CompletableFuture<SendResult> toCompletedFuture() {
270+
return CompletableFuture.completedFuture(this);
271+
}
272+
273+
static CompletableFuture<SendResult> failed(@Nullable String message) {
274+
return new SendResult(false, message).toCompletedFuture();
275+
}
276+
277+
static CompletableFuture<SendResult> succeeded(boolean success) {
278+
return new SendResult(success, null).toCompletedFuture();
279+
}
280+
}

0 commit comments

Comments
 (0)