Skip to content

Commit 6ab6a42

Browse files
committed
Add Dynamic loading support to fiam.
The change adds Analytics load detection.
1 parent 00e9d49 commit 6ab6a42

File tree

7 files changed

+320
-102
lines changed

7 files changed

+320
-102
lines changed

firebase-inappmessaging/firebase-inappmessaging.gradle

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ dependencies {
130130
implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'
131131
implementation 'com.google.auto.value:auto-value-annotations:1.6.6'
132132

133-
implementation('com.google.firebase:firebase-measurement-connector:18.0.0') {
133+
implementation('com.google.firebase:firebase-measurement-connector:18.0.2') {
134134
exclude group: 'com.google.firebase', module: 'firebase-common'
135135
}
136136

@@ -142,10 +142,11 @@ dependencies {
142142
annotationProcessor 'com.google.auto.value:auto-value:1.6.5'
143143
annotationProcessor 'com.ryanharter.auto.value:auto-value-parcel:0.2.6'
144144

145-
testImplementation 'org.mockito:mockito-core:1.10.19'
145+
testImplementation 'org.mockito:mockito-core:3.3.3'
146146
testImplementation "com.google.truth:truth:$googleTruthVersion"
147-
testImplementation 'junit:junit:4.12'
148-
testImplementation 'androidx.test:runner:1.2.0'
147+
testImplementation 'junit:junit:4.13.1'
148+
testImplementation 'androidx.test:runner:1.3.0'
149+
testImplementation 'androidx.test.ext:junit:1.1.2'
149150
testImplementation ("org.robolectric:robolectric:$robolectricVersion") {
150151
exclude group: 'com.google.protobuf', module: 'protobuf-java'
151152
}

firebase-inappmessaging/src/androidTest/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingFlowableTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,8 @@ public void setUp() {
265265
.testForegroundFlowableModule(new TestForegroundFlowableModule(foregroundNotifier))
266266
.applicationModule(new ApplicationModule(application))
267267
.appMeasurementModule(
268-
new AppMeasurementModule(analyticsConnector, firebaseEventSubscriber))
268+
new AppMeasurementModule(
269+
p -> p.handle(() -> analyticsConnector), firebaseEventSubscriber))
269270
.testSystemClockModule(new TestSystemClockModule(NOW))
270271
.programmaticContextualTriggerFlowableModule(
271272
new ProgrammaticContextualTriggerFlowableModule(
@@ -313,7 +314,7 @@ public void onAnalyticsNotification_notifiesSubscriber() {
313314
public void onAppOpen_whenAnalyticsAbsent_notifiesSubscriber() {
314315
TestUniversalComponent analyticsLessUniversalComponent =
315316
universalComponentBuilder
316-
.appMeasurementModule(new AppMeasurementModule(null, firebaseEventSubscriber))
317+
.appMeasurementModule(new AppMeasurementModule(handler -> {}, firebaseEventSubscriber))
317318
.build();
318319
TestAppComponent appComponent =
319320
appComponentBuilder.universalComponent(analyticsLessUniversalComponent).build();

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/FirebaseInAppMessagingRegistrar.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import com.google.firebase.inappmessaging.internal.injection.modules.ApplicationModule;
4040
import com.google.firebase.inappmessaging.internal.injection.modules.GrpcClientModule;
4141
import com.google.firebase.inappmessaging.internal.injection.modules.ProgrammaticContextualTriggerFlowableModule;
42+
import com.google.firebase.inject.Deferred;
4243
import com.google.firebase.installations.FirebaseInstallationsApi;
4344
import com.google.firebase.platforminfo.LibraryVersionComponent;
4445
import java.util.Arrays;
@@ -60,7 +61,7 @@ public List<Component<?>> getComponents() {
6061
.add(Dependency.required(FirebaseInstallationsApi.class))
6162
.add(Dependency.required(FirebaseApp.class))
6263
.add(Dependency.required(AbtComponent.class))
63-
.add(Dependency.optional(AnalyticsConnector.class))
64+
.add(Dependency.deferred(AnalyticsConnector.class))
6465
.add(Dependency.required(TransportFactory.class))
6566
.add(Dependency.required(Subscriber.class))
6667
.factory(this::providesFirebaseInAppMessaging)
@@ -72,7 +73,8 @@ public List<Component<?>> getComponents() {
7273
private FirebaseInAppMessaging providesFirebaseInAppMessaging(ComponentContainer container) {
7374
FirebaseApp firebaseApp = container.get(FirebaseApp.class);
7475
FirebaseInstallationsApi firebaseInstallations = container.get(FirebaseInstallationsApi.class);
75-
AnalyticsConnector analyticsConnector = container.get(AnalyticsConnector.class);
76+
Deferred<AnalyticsConnector> analyticsConnector =
77+
container.getDeferred(AnalyticsConnector.class);
7678
Subscriber firebaseEventsSubscriber = container.get(Subscriber.class);
7779

7880
Application application = (Application) firebaseApp.getApplicationContext();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
// Copyright 2018 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.inappmessaging.internal;
16+
17+
import android.os.Bundle;
18+
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
20+
import com.google.firebase.analytics.connector.AnalyticsConnector;
21+
import com.google.firebase.inject.Deferred;
22+
import java.util.Collections;
23+
import java.util.HashSet;
24+
import java.util.List;
25+
import java.util.Map;
26+
import java.util.Set;
27+
28+
/**
29+
* Proxy connector that delegates to analytics when it's available.
30+
*
31+
* <p>For a subset of functionality it also caches calls and propagates them to analytics once it
32+
* loads.
33+
*/
34+
public class ProxyAnalyticsConnector implements AnalyticsConnector {
35+
private volatile Object instance;
36+
37+
public ProxyAnalyticsConnector(Deferred<AnalyticsConnector> analyticsConnector) {
38+
instance = analyticsConnector;
39+
analyticsConnector.whenAvailable(connectorProvider -> instance = connectorProvider.get());
40+
}
41+
42+
private AnalyticsConnector safeGet() {
43+
Object result = instance;
44+
if (result instanceof AnalyticsConnector) {
45+
return (AnalyticsConnector) result;
46+
}
47+
return null;
48+
}
49+
50+
@Override
51+
public void logEvent(@NonNull String s, @NonNull String s1, @NonNull Bundle bundle) {
52+
AnalyticsConnector connector = safeGet();
53+
if (connector != null) {
54+
connector.logEvent(s, s1, bundle);
55+
}
56+
}
57+
58+
@Override
59+
public void setUserProperty(@NonNull String s, @NonNull String s1, @NonNull Object o) {
60+
AnalyticsConnector connector = safeGet();
61+
if (connector != null) {
62+
connector.setUserProperty(s, s1, o);
63+
}
64+
}
65+
66+
// Not implemented since it's not used by fiam
67+
@NonNull
68+
@Override
69+
public Map<String, Object> getUserProperties(boolean b) {
70+
return Collections.emptyMap();
71+
}
72+
73+
@NonNull
74+
@Override
75+
public AnalyticsConnectorHandle registerAnalyticsConnectorListener(
76+
@NonNull String s, @NonNull AnalyticsConnectorListener analyticsConnectorListener) {
77+
Object result = instance;
78+
if (result instanceof AnalyticsConnector) {
79+
return ((AnalyticsConnector) result)
80+
.registerAnalyticsConnectorListener(s, analyticsConnectorListener);
81+
}
82+
@SuppressWarnings("unchecked")
83+
Deferred<AnalyticsConnector> deferred = (Deferred<AnalyticsConnector>) result;
84+
return new ProxyAnalyticsConnectorHandle(s, analyticsConnectorListener, deferred);
85+
}
86+
87+
// Not implemented since it's not used by fiam.
88+
@Override
89+
public void setConditionalUserProperty(
90+
@NonNull ConditionalUserProperty conditionalUserProperty) {}
91+
92+
// Not implemented since it's not used by fiam.
93+
@Override
94+
public void clearConditionalUserProperty(
95+
@NonNull String s, @Nullable String s1, @Nullable Bundle bundle) {}
96+
97+
// Not implemented since it's not used by fiam.
98+
@NonNull
99+
@Override
100+
public List<ConditionalUserProperty> getConditionalUserProperties(
101+
@NonNull String s, @Nullable String s1) {
102+
return Collections.emptyList();
103+
}
104+
105+
// Not implemented since it's not used by fiam.
106+
@Override
107+
public int getMaxUserProperties(@NonNull String s) {
108+
return 0;
109+
}
110+
111+
private static class ProxyAnalyticsConnectorHandle implements AnalyticsConnectorHandle {
112+
private static final Object UNREGISTERED = new Object();
113+
private Set<String> eventNames = new HashSet<>();
114+
private Object instance;
115+
116+
private ProxyAnalyticsConnectorHandle(
117+
String s,
118+
AnalyticsConnectorListener listener,
119+
Deferred<AnalyticsConnector> analyticsConnector) {
120+
analyticsConnector.whenAvailable(
121+
connectorProvider -> {
122+
synchronized (ProxyAnalyticsConnectorHandle.this) {
123+
if (instance == UNREGISTERED) {
124+
return;
125+
}
126+
AnalyticsConnector connector = connectorProvider.get();
127+
AnalyticsConnectorHandle handle =
128+
connector.registerAnalyticsConnectorListener(s, listener);
129+
instance = handle;
130+
if (!eventNames.isEmpty()) {
131+
handle.registerEventNames(eventNames);
132+
eventNames = new HashSet<>();
133+
}
134+
}
135+
});
136+
}
137+
138+
@Override
139+
public synchronized void unregister() {
140+
if (instance == UNREGISTERED) {
141+
return;
142+
}
143+
if (instance != null) {
144+
AnalyticsConnectorHandle handle = (AnalyticsConnectorHandle) this.instance;
145+
handle.unregister();
146+
}
147+
instance = UNREGISTERED;
148+
eventNames.clear();
149+
}
150+
151+
@Override
152+
public synchronized void registerEventNames(@NonNull Set<String> set) {
153+
if (instance == UNREGISTERED) {
154+
return;
155+
}
156+
if (instance != null) {
157+
AnalyticsConnectorHandle handle = (AnalyticsConnectorHandle) this.instance;
158+
handle.registerEventNames(set);
159+
return;
160+
}
161+
eventNames.addAll(set);
162+
}
163+
164+
@Override
165+
public synchronized void unregisterEventNames() {
166+
if (instance == UNREGISTERED) {
167+
return;
168+
}
169+
if (instance != null) {
170+
AnalyticsConnectorHandle handle = (AnalyticsConnectorHandle) this.instance;
171+
handle.unregisterEventNames();
172+
return;
173+
}
174+
eventNames.clear();
175+
}
176+
}
177+
}

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/internal/StubAnalyticsConnector.java

Lines changed: 0 additions & 88 deletions
This file was deleted.

firebase-inappmessaging/src/main/java/com/google/firebase/inappmessaging/internal/injection/modules/AppMeasurementModule.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
import com.google.firebase.analytics.connector.AnalyticsConnector;
1818
import com.google.firebase.events.Subscriber;
19-
import com.google.firebase.inappmessaging.internal.StubAnalyticsConnector;
19+
import com.google.firebase.inappmessaging.internal.ProxyAnalyticsConnector;
20+
import com.google.firebase.inject.Deferred;
2021
import dagger.Module;
2122
import dagger.Provides;
2223
import javax.inject.Singleton;
@@ -29,13 +30,12 @@
2930
@Module
3031
public class AppMeasurementModule {
3132

32-
private AnalyticsConnector analyticsConnector;
33-
private Subscriber firebaseEventsSubscriber;
33+
private final AnalyticsConnector analyticsConnector;
34+
private final Subscriber firebaseEventsSubscriber;
3435

3536
public AppMeasurementModule(
36-
AnalyticsConnector analyticsConnector, Subscriber firebaseEventsSubscriber) {
37-
this.analyticsConnector =
38-
analyticsConnector != null ? analyticsConnector : StubAnalyticsConnector.instance;
37+
Deferred<AnalyticsConnector> analyticsConnector, Subscriber firebaseEventsSubscriber) {
38+
this.analyticsConnector = new ProxyAnalyticsConnector(analyticsConnector);
3939
this.firebaseEventsSubscriber = firebaseEventsSubscriber;
4040
}
4141

0 commit comments

Comments
 (0)