Skip to content

Commit ad452fa

Browse files
committed
❇️ Added video recording feature
1 parent b32115d commit ad452fa

File tree

19 files changed

+2086
-154
lines changed

19 files changed

+2086
-154
lines changed

README.md

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ implementation 'io.github.middleware-labs:android-sdk:1.0.1'
5959

6060
```java
6161

62-
class MyApplication extends Application {
62+
class MiddlewareApplication extends Application {
6363
private final String targetUrl = "<target-url>";
6464
private final String rumAccessToken = "<your-access-token>";
6565

@@ -243,4 +243,26 @@ logInstance.e("TAG", "I am error");
243243
logInstance.i("TAG", "I am info");
244244
logInstance.w("TAG", "I am warn");
245245
```
246+
### Enable Video Recording
247+
Enable video recording in activity the following are the steps to enable.
248+
Override the `onResume` & `onPause` methods to start a& stop video recording respectively.
246249

250+
NOTE: This feature is available above Android Nougat
251+
252+
```java
253+
final MiddlewareRecorder recorder = Middleware.getInstance().getRecorder();
254+
255+
@RequiresApi(api = Build.VERSION_CODES.N)
256+
@Override
257+
protected void onResume() {
258+
super.onResume();
259+
recorder.startRecording(this);
260+
}
261+
262+
@RequiresApi(api = Build.VERSION_CODES.N)
263+
@Override
264+
protected void onPause() {
265+
super.onPause();
266+
recorder.stopRecording();
267+
}
268+
```

app/src/main/java/io/middleware/android/sample/MainActivity.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
import android.annotation.SuppressLint;
66
import android.content.Intent;
7+
import android.os.Build;
78
import android.os.Bundle;
89
import android.widget.Button;
910
import android.widget.Toast;
1011

1112
import androidx.annotation.NonNull;
13+
import androidx.annotation.RequiresApi;
1214
import androidx.appcompat.app.AppCompatActivity;
1315
import androidx.lifecycle.MutableLiveData;
1416

@@ -17,6 +19,7 @@
1719
import java.util.concurrent.TimeUnit;
1820

1921
import io.middleware.android.sdk.Middleware;
22+
import io.middleware.android.sdk.core.replay.MiddlewareRecorder;
2023
import io.opentelemetry.api.common.AttributeKey;
2124
import io.opentelemetry.api.common.Attributes;
2225
import io.opentelemetry.api.events.EventEmitter;
@@ -33,12 +36,26 @@
3336
import okhttp3.Response;
3437
import okhttp3.ResponseBody;
3538

39+
@RequiresApi(api = Build.VERSION_CODES.N)
3640
public class MainActivity extends AppCompatActivity {
3741

3842
private Call.Factory okHttpClient;
3943
private final MutableLiveData<String> httpResponse = new MutableLiveData<>();
4044
private Middleware middleware;
4145
int count = 0;
46+
private MiddlewareRecorder recorder = Middleware.getInstance().getRecorder();
47+
48+
@Override
49+
protected void onResume() {
50+
super.onResume();
51+
recorder.startRecording(this);
52+
}
53+
54+
@Override
55+
protected void onPause() {
56+
super.onPause();
57+
recorder.stopRecording();
58+
}
4259

4360
@Override
4461
protected void onCreate(Bundle savedInstanceState) {

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22
plugins {
3-
id 'com.android.application' version '8.1.2' apply false
3+
id 'com.android.application' version '8.1.2' apply false
44
id 'com.android.library' version '8.1.2' apply false
55
}

sdk/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
mavenPublishing {
7-
coordinates("io.github.middleware-labs", "android-sdk", "1.0.1")
7+
coordinates("io.github.middleware-labs", "android-sdk", "1.0.2")
88

99
pom {
1010
name = "Middleware Android RUM SDK"
@@ -78,7 +78,8 @@ dependencies {
7878
implementation 'io.opentelemetry:opentelemetry-extension-trace-propagators:1.32.0'
7979
api "com.squareup.okhttp3:okhttp:4.12.0"
8080
implementation "io.opentelemetry.instrumentation:opentelemetry-okhttp-3.0"
81-
implementation 'androidx.work:work-runtime:2.8.1'
81+
implementation 'androidx.work:work-runtime:2.9.0'
82+
implementation 'com.github.ChickenHook:RestrictionBypass:2.2'
8283
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.3"
8384

8485
testImplementation('org.mockito:mockito-core:5.7.0')

sdk/src/main/java/io/middleware/android/sdk/Middleware.java

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,15 @@
1111

1212
import android.app.Application;
1313
import android.location.Location;
14+
import android.os.Build;
1415
import android.os.Handler;
1516
import android.os.Looper;
1617
import android.util.Log;
1718
import android.webkit.WebView;
1819

1920
import androidx.annotation.NonNull;
2021
import androidx.annotation.Nullable;
22+
import androidx.annotation.RequiresApi;
2123

2224
import java.util.concurrent.TimeUnit;
2325
import java.util.function.Consumer;
@@ -27,6 +29,8 @@
2729
import io.middleware.android.sdk.core.RumInitializer;
2830
import io.middleware.android.sdk.core.RumSetup;
2931
import io.middleware.android.sdk.core.models.NativeRumSessionId;
32+
import io.middleware.android.sdk.core.replay.MiddlewareRecorder;
33+
import io.middleware.android.sdk.core.replay.ReplayRecording;
3034
import io.middleware.android.sdk.extractors.RumResponseAttributesExtractor;
3135
import io.middleware.android.sdk.interfaces.IMiddleware;
3236
import io.middleware.android.sdk.utils.ServerTimingHeaderParser;
@@ -42,8 +46,6 @@
4246
import io.opentelemetry.api.logs.Severity;
4347
import io.opentelemetry.api.trace.Span;
4448
import io.opentelemetry.api.trace.Tracer;
45-
import io.opentelemetry.context.Context;
46-
import io.opentelemetry.context.Scope;
4749
import io.opentelemetry.instrumentation.okhttp.v3_0.OkHttpTelemetry;
4850
import io.opentelemetry.sdk.OpenTelemetrySdk;
4951
import okhttp3.Call;
@@ -118,6 +120,18 @@ public static Middleware getInstance() {
118120
return INSTANCE;
119121
}
120122

123+
/**
124+
* Returns the MiddlewareRecording enables recording functionality on activity.
125+
* NOTE: This api is available above Android Nougat version.
126+
*
127+
* @return MiddlewareRecorder
128+
*/
129+
@RequiresApi(api = Build.VERSION_CODES.N)
130+
@Override
131+
public MiddlewareRecorder getRecorder() {
132+
return new MiddlewareRecorder(this);
133+
}
134+
121135
/**
122136
* Wrap the provided {@link OkHttpClient} with OpenTelemetry and RUM instrumentation. Since
123137
* {@link Call.Factory} is the primary useful interface implemented by the OkHttpClient, this
@@ -162,17 +176,17 @@ public String getRumSessionId() {
162176
}
163177

164178
//NOTE: This method is not used as of now will be used in future purposes.
165-
private void addRumEvent(String name, Attributes attributes) {
179+
public void addRumEvent(ReplayRecording replayRecording, Attributes attributes) {
166180
if (isInitialized()) {
167-
INSTANCE.sendRumEvent(name, attributes);
181+
INSTANCE.sendRumEvent(replayRecording, attributes);
168182
} else {
169183
Log.d(RUM_TRACER_NAME, "Unable to send rum event setup is not done properly.");
170184
}
171185
}
172186

173-
private void sendRumEvent(String name, Attributes attributes) {
187+
private void sendRumEvent(ReplayRecording replayRecording, Attributes attributes) {
174188
attributes.toBuilder().put("session.id", getRumSessionId());
175-
rumInitializer.sendRumEvent(name, attributes);
189+
rumInitializer.sendRumEvent(replayRecording, attributes);
176190
}
177191

178192
/**

sdk/src/main/java/io/middleware/android/sdk/core/RumInitializer.java

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
import android.os.Looper;
1414
import android.util.Log;
1515

16+
import androidx.annotation.NonNull;
17+
1618
import com.google.gson.Gson;
1719

20+
import java.io.IOException;
1821
import java.text.SimpleDateFormat;
1922
import java.time.LocalDateTime;
2023
import java.time.ZoneId;
@@ -27,7 +30,7 @@
2730
import io.middleware.android.sdk.builders.MiddlewareBuilder;
2831
import io.middleware.android.sdk.core.models.InitializationEvents;
2932
import io.middleware.android.sdk.core.models.RumData;
30-
import io.middleware.android.sdk.core.services.RumServiceManager;
33+
import io.middleware.android.sdk.core.replay.ReplayRecording;
3134
import io.middleware.android.sdk.interfaces.IRum;
3235
import io.middleware.android.sdk.messages.Rum;
3336
import io.middleware.android.sdk.messages.RumMessage;
@@ -41,6 +44,13 @@
4144
import io.opentelemetry.api.common.Attributes;
4245
import io.opentelemetry.sdk.resources.Resource;
4346
import io.opentelemetry.sdk.resources.ResourceBuilder;
47+
import okhttp3.Call;
48+
import okhttp3.Callback;
49+
import okhttp3.MediaType;
50+
import okhttp3.OkHttpClient;
51+
import okhttp3.Request;
52+
import okhttp3.RequestBody;
53+
import okhttp3.Response;
4454

4555
public class RumInitializer implements IRum {
4656
private final MiddlewareBuilder builder;
@@ -116,41 +126,55 @@ public Middleware initialize(Function<Application, CurrentNetworkProvider> curre
116126
return new Middleware(openTelemetryRum, rumSetup, globalAttributesSpanAppender);
117127
}
118128

119-
@SuppressLint("ObsoleteSdkInt")
120-
public void sendRumEvent(String name, Attributes attributes) {
121-
String timestamp;
122-
123-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
124-
LocalDateTime utcDateTime = LocalDateTime.now(ZoneId.of("UTC"));
125-
timestamp = utcDateTime.toString();
126-
} else {
127-
@SuppressLint("SimpleDateFormat") SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
128-
df.setTimeZone(TimeZone.getTimeZone("UTC"));
129-
Calendar c = Calendar.getInstance();
130-
timestamp = df.format(c.getTime());
131-
}
132-
RumMessage rumMessage = new RumMessage.Builder(name)
133-
.setAttributes(attributes)
134-
.timestamp(timestamp)
129+
public void sendRumEvent(ReplayRecording replayRecording, Attributes attributes) {
130+
RumMessage rumMessage = new RumMessage.Builder()
131+
.events(replayRecording.getPayload())
135132
.sessionId(attributes.get(AttributeKey.stringKey("session.id")))
136133
.version(RumUtil.getVersion(Objects.requireNonNull(application)))
137-
.os("Android")
138-
.osVersion(Build.VERSION.RELEASE)
139-
.platform(String.format("%s %s", Build.MANUFACTURER, Build.MODEL))
140134
.build();
141135

142-
final Rum rum = new Rum();
143-
rum.setEventData(new RumMessage[]{rumMessage});
144136
final RumData rumData = new RumData();
145137
rumData.setAccessToken(builder.rumAccessToken);
146138
rumData.setEndpoint(builder.target + "/v1/metrics/rum");
147-
rumData.setPayload(new Gson().toJson(rum));
139+
rumData.setPayload(new Gson().toJson(rumMessage));
148140
startRumService(rumData);
149141
}
150142

151143
private void startRumService(RumData rumData) {
152144
Log.d("Middleware", "Starting RUM Service to send rum data");
153-
RumServiceManager.startWorker(application.getApplicationContext(), rumData);
145+
postRum(rumData);
146+
}
147+
148+
private void postRum(RumData rumData) {
149+
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
150+
MediaType MEDIA_TYPE_JSON = MediaType.parse("application/json; charset=utf-8");
151+
RequestBody requestBody = RequestBody.Companion.create(rumData.getPayload(), MEDIA_TYPE_JSON);
152+
Request request = new Request.Builder()
153+
.url(rumData.getEndpoint())
154+
.header("Origin", builder.projectName)
155+
.header("MW_API_KEY", rumData.getAccessToken())
156+
.header("Content-Type", "application/json")
157+
.post(requestBody)
158+
.build();
159+
try {
160+
okHttpClient.newCall(request).enqueue(new Callback() {
161+
@Override
162+
public void onFailure(@NonNull Call call, @NonNull IOException e) {
163+
e.printStackTrace();
164+
}
165+
166+
@Override
167+
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
168+
if (response.isSuccessful()) {
169+
Log.d("RumService", "Video Recorded Successfully" + response.code());
170+
}
171+
assert response.body() != null;
172+
response.body().close();
173+
}
174+
});
175+
} catch (Exception e) {
176+
e.printStackTrace();
177+
}
154178
}
155179

156180
private Resource createMiddlewareResource() {

0 commit comments

Comments
 (0)