Skip to content

Commit e33bcad

Browse files
committed
Use Dagger in firebase-appdistribution (#4540)
1 parent c9c3a20 commit e33bcad

29 files changed

+303
-278
lines changed

firebase-appdistribution/firebase-appdistribution.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
plugins {
1616
id 'firebase-library'
17+
id 'firebase-vendor'
1718
}
1819

1920
firebaseLibrary {
@@ -54,6 +55,12 @@ dependencies {
5455
testImplementation project(':integ-testing')
5556
runtimeOnly project(':firebase-installations')
5657

58+
implementation 'javax.inject:javax.inject:1'
59+
vendor ('com.google.dagger:dagger:2.43.2') {
60+
exclude group: "javax.inject", module: "javax.inject"
61+
}
62+
annotationProcessor 'com.google.dagger:dagger-compiler:2.43.2'
63+
5764
testImplementation 'junit:junit:4.13.2'
5865
testImplementation "org.robolectric:robolectric:$robolectricVersion"
5966
testImplementation "com.google.truth:truth:$googleTruthVersion"

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/AabUpdater.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import com.google.firebase.appdistribution.UpdateTask;
3232
import java.io.IOException;
3333
import java.util.concurrent.Executor;
34+
import javax.inject.Inject;
3435
import javax.net.ssl.HttpsURLConnection;
3536

3637
/** Class that handles updateApp functionality for AABs in {@link FirebaseAppDistribution}. */
@@ -46,13 +47,7 @@ class AabUpdater {
4647
private AppDistributionReleaseInternal aabReleaseInProgress;
4748
private boolean hasBeenSentToPlayForCurrentTask = false;
4849

49-
AabUpdater(
50-
@NonNull FirebaseAppDistributionLifecycleNotifier lifecycleNotifier,
51-
@NonNull @Blocking Executor blockingExecutor,
52-
@NonNull @Lightweight Executor lightweightExecutor) {
53-
this(lifecycleNotifier, new HttpsUrlConnectionFactory(), blockingExecutor, lightweightExecutor);
54-
}
55-
50+
@Inject
5651
AabUpdater(
5752
@NonNull FirebaseAppDistributionLifecycleNotifier lifecycleNotifier,
5853
@NonNull HttpsUrlConnectionFactory httpsUrlConnectionFactory,

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/ApkInstaller.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,25 @@
1717
import android.app.Activity;
1818
import android.content.Intent;
1919
import androidx.annotation.Nullable;
20-
import androidx.annotation.VisibleForTesting;
2120
import com.google.android.gms.tasks.Task;
2221
import com.google.android.gms.tasks.TaskCompletionSource;
2322
import com.google.firebase.annotations.concurrent.Lightweight;
2423
import com.google.firebase.appdistribution.FirebaseAppDistribution;
2524
import com.google.firebase.appdistribution.FirebaseAppDistributionException;
2625
import java.util.concurrent.Executor;
26+
import javax.inject.Inject;
2727

2828
/** Class that handles installing APKs in {@link FirebaseAppDistribution}. */
2929
class ApkInstaller {
3030
private static final String TAG = "ApkInstaller";
3131

32-
private final FirebaseAppDistributionLifecycleNotifier lifeCycleNotifier;
3332
private final TaskCompletionSourceCache<Void> installTaskCompletionSourceCache;
34-
private final @Lightweight Executor lightweightExecutor;
3533

36-
@VisibleForTesting
34+
@Inject
3735
ApkInstaller(
3836
FirebaseAppDistributionLifecycleNotifier lifeCycleNotifier,
3937
@Lightweight Executor lightweightExecutor) {
40-
this.lifeCycleNotifier = lifeCycleNotifier;
4138
this.installTaskCompletionSourceCache = new TaskCompletionSourceCache<>(lightweightExecutor);
42-
this.lightweightExecutor = lightweightExecutor;
4339
lifeCycleNotifier.addOnActivityDestroyedListener(this::onActivityDestroyed);
4440
}
4541

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/ApkUpdater.java

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import androidx.annotation.NonNull;
2424
import androidx.annotation.VisibleForTesting;
2525
import com.google.android.gms.tasks.Task;
26-
import com.google.firebase.FirebaseApp;
2726
import com.google.firebase.annotations.concurrent.Blocking;
2827
import com.google.firebase.annotations.concurrent.Lightweight;
2928
import com.google.firebase.appdistribution.FirebaseAppDistribution;
@@ -37,6 +36,7 @@
3736
import java.io.InputStream;
3837
import java.util.concurrent.Executor;
3938
import java.util.jar.JarFile;
39+
import javax.inject.Inject;
4040
import javax.net.ssl.HttpsURLConnection;
4141

4242
/** Class that handles updateApp functionality for APKs in {@link FirebaseAppDistribution}. */
@@ -55,24 +55,8 @@ class ApkUpdater {
5555
private final FirebaseAppDistributionLifecycleNotifier lifeCycleNotifier;
5656
private UpdateTaskCache cachedUpdateTask;
5757

58-
public ApkUpdater(
59-
@NonNull FirebaseApp firebaseApp,
60-
@NonNull ApkInstaller apkInstaller,
61-
@NonNull FirebaseAppDistributionLifecycleNotifier lifeCycleNotifier,
62-
@NonNull @Blocking Executor blockingExecutor,
63-
@NonNull @Lightweight Executor lightweightExecutor) {
64-
this(
65-
firebaseApp.getApplicationContext(),
66-
apkInstaller,
67-
new FirebaseAppDistributionNotificationsManager(firebaseApp.getApplicationContext()),
68-
new HttpsUrlConnectionFactory(),
69-
lifeCycleNotifier,
70-
blockingExecutor,
71-
lightweightExecutor);
72-
}
73-
74-
@VisibleForTesting
75-
public ApkUpdater(
58+
@Inject
59+
ApkUpdater(
7660
@NonNull Context context,
7761
@NonNull ApkInstaller apkInstaller,
7862
@NonNull FirebaseAppDistributionNotificationsManager appDistributionNotificationsManager,
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright 2022 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.appdistribution.impl;
16+
17+
import android.content.Context;
18+
import com.google.firebase.FirebaseApp;
19+
import com.google.firebase.FirebaseOptions;
20+
import com.google.firebase.annotations.concurrent.Background;
21+
import com.google.firebase.annotations.concurrent.Blocking;
22+
import com.google.firebase.annotations.concurrent.Lightweight;
23+
import com.google.firebase.annotations.concurrent.UiThread;
24+
import com.google.firebase.appdistribution.FirebaseAppDistribution;
25+
import com.google.firebase.inject.Provider;
26+
import com.google.firebase.installations.FirebaseInstallationsApi;
27+
import dagger.Binds;
28+
import dagger.BindsInstance;
29+
import dagger.Component;
30+
import dagger.Module;
31+
import java.util.concurrent.Executor;
32+
import javax.inject.Singleton;
33+
34+
@Component(modules = AppDistroComponent.MainModule.class)
35+
@Singleton
36+
interface AppDistroComponent {
37+
38+
/** Get the default instance of AppDistroComponent. */
39+
static AppDistroComponent getInstance() {
40+
// TODO(lkellogg): Support multiple FirebaseApp instances
41+
return FirebaseApp.getInstance().get(AppDistroComponent.class);
42+
}
43+
44+
// Provided classes
45+
FirebaseAppDistribution getAppDistribution();
46+
47+
FirebaseAppDistributionLifecycleNotifier getLifecycleNotifier();
48+
49+
// Provided instances
50+
@Component.Builder
51+
interface Builder {
52+
53+
@BindsInstance
54+
Builder setApplicationContext(Context context);
55+
56+
@BindsInstance
57+
Builder setOptions(FirebaseOptions options);
58+
59+
@BindsInstance
60+
Builder setApp(FirebaseApp app);
61+
62+
@BindsInstance
63+
Builder setFis(Provider<FirebaseInstallationsApi> fis);
64+
65+
@BindsInstance
66+
Builder setBackgroundExecutor(@Background Executor executor);
67+
68+
@BindsInstance
69+
Builder setBlockingExecutor(@Blocking Executor executor);
70+
71+
@BindsInstance
72+
Builder setLightweightExecutor(@Lightweight Executor executor);
73+
74+
@BindsInstance
75+
Builder setUiThreadExecutor(@UiThread Executor executor);
76+
77+
AppDistroComponent build();
78+
}
79+
80+
// Activity injectors
81+
void inject(FeedbackActivity activity);
82+
83+
void inject(TakeScreenshotAndStartFeedbackActivity activity);
84+
85+
@Module
86+
interface MainModule {
87+
@Binds
88+
FirebaseAppDistribution bindAppDistro(FirebaseAppDistributionImpl impl);
89+
}
90+
}

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/AppIconSource.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,16 @@
2121
import android.os.Build;
2222
import android.os.Build.VERSION;
2323
import androidx.core.content.ContextCompat;
24+
import javax.inject.Inject;
2425

2526
class AppIconSource {
2627
private static final String TAG = "AppIconSource";
2728

2829
private static final int DEFAULT_ICON = android.R.drawable.sym_def_app_icon;
2930

31+
@Inject
32+
AppIconSource() {}
33+
3034
/**
3135
* Get an icon for the given app context, or a default icon if the app icon is adaptive or does
3236
* not exist.

firebase-appdistribution/src/main/java/com/google/firebase/appdistribution/impl/FeedbackActivity.java

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import static android.view.View.GONE;
1818
import static android.view.View.VISIBLE;
1919

20-
import android.annotation.SuppressLint;
2120
import android.graphics.Bitmap;
2221
import android.net.Uri;
2322
import android.os.Bundle;
@@ -31,7 +30,11 @@
3130
import androidx.annotation.NonNull;
3231
import androidx.annotation.Nullable;
3332
import androidx.appcompat.app.AppCompatActivity;
33+
import com.google.firebase.annotations.concurrent.Blocking;
34+
import com.google.firebase.annotations.concurrent.UiThread;
3435
import java.io.IOException;
36+
import java.util.concurrent.Executor;
37+
import javax.inject.Inject;
3538

3639
/** Activity for tester to compose and submit feedback. */
3740
public class FeedbackActivity extends AppCompatActivity {
@@ -46,16 +49,21 @@ public class FeedbackActivity extends AppCompatActivity {
4649
public static final String SCREENSHOT_URI_KEY =
4750
"com.google.firebase.appdistribution.FeedbackActivity.SCREENSHOT_URI";
4851

49-
private FeedbackSender feedbackSender;
52+
@Inject FeedbackSender feedbackSender;
53+
@Inject @Blocking Executor blockingExecutor;
54+
@Inject @UiThread Executor uiThreadExecutor;
55+
5056
@Nullable private String releaseName; // in development-mode the releaseName might be null
5157
private CharSequence infoText;
5258
@Nullable private Uri screenshotUri;
5359

5460
@Override
5561
protected void onCreate(Bundle savedInstanceState) {
62+
// Inject members before calling super.onCreate to avoid issues with fragment restoration
63+
AppDistroComponent.getInstance().inject(this);
64+
5665
super.onCreate(savedInstanceState);
5766

58-
feedbackSender = FeedbackSender.getInstance();
5967
if (savedInstanceState != null) {
6068
releaseName = savedInstanceState.getString(RELEASE_NAME_KEY);
6169
infoText = savedInstanceState.getCharSequence(INFO_TEXT_KEY);
@@ -96,33 +104,31 @@ private void setupView() {
96104
}
97105

98106
private void setupScreenshot() {
99-
feedbackSender
100-
.getBlockingExecutor()
101-
.execute(
102-
() -> {
103-
// do I/O on separate thread in order to not block the UI
104-
Bitmap screenshot = screenshotUri == null ? null : readScreenshot();
105-
if (screenshot != null) {
106-
runOnUiThread(
107-
() -> {
108-
ImageView imageView = findViewById(R.id.screenshotImageView);
109-
imageView.setImageBitmap(screenshot);
110-
CheckBox checkBox = findViewById(R.id.screenshotCheckBox);
111-
checkBox.setChecked(true);
112-
checkBox.setOnClickListener(
113-
v -> imageView.setVisibility(checkBox.isChecked() ? VISIBLE : GONE));
114-
});
115-
} else {
116-
LogWrapper.e(TAG, "No screenshot available");
117-
runOnUiThread(
118-
() -> {
119-
CheckBox checkBox = findViewById(R.id.screenshotCheckBox);
120-
checkBox.setText(R.string.no_screenshot);
121-
checkBox.setClickable(false);
122-
checkBox.setChecked(false);
123-
});
124-
}
125-
});
107+
blockingExecutor.execute(
108+
() -> {
109+
// do I/O on separate thread in order to not block the UI
110+
Bitmap screenshot = screenshotUri == null ? null : readScreenshot();
111+
if (screenshot != null) {
112+
runOnUiThread(
113+
() -> {
114+
ImageView imageView = findViewById(R.id.screenshotImageView);
115+
imageView.setImageBitmap(screenshot);
116+
CheckBox checkBox = findViewById(R.id.screenshotCheckBox);
117+
checkBox.setChecked(true);
118+
checkBox.setOnClickListener(
119+
v -> imageView.setVisibility(checkBox.isChecked() ? VISIBLE : GONE));
120+
});
121+
} else {
122+
LogWrapper.e(TAG, "No screenshot available");
123+
runOnUiThread(
124+
() -> {
125+
CheckBox checkBox = findViewById(R.id.screenshotCheckBox);
126+
checkBox.setText(R.string.no_screenshot);
127+
checkBox.setClickable(false);
128+
checkBox.setChecked(false);
129+
});
130+
}
131+
});
126132
}
127133

128134
@Nullable
@@ -145,8 +151,6 @@ private Bitmap readScreenshot() {
145151
return bitmap;
146152
}
147153

148-
// TODO(b/261014422): Use an explicit executor in continuations.
149-
@SuppressLint("TaskMainThread")
150154
public void submitFeedback(View view) {
151155
setSubmittingStateEnabled(true);
152156
if (releaseName == null) {
@@ -163,12 +167,14 @@ public void submitFeedback(View view) {
163167
feedbackText.getText().toString(),
164168
screenshotCheckBox.isChecked() ? screenshotUri : null)
165169
.addOnSuccessListener(
170+
uiThreadExecutor,
166171
unused -> {
167172
LogWrapper.i(TAG, "Feedback submitted");
168173
Toast.makeText(this, "Feedback submitted", Toast.LENGTH_LONG).show();
169174
finish();
170175
})
171176
.addOnFailureListener(
177+
uiThreadExecutor,
172178
e -> {
173179
LogWrapper.e(TAG, "Failed to submit feedback", e);
174180
Toast.makeText(this, "Error submitting feedback", Toast.LENGTH_LONG).show();

0 commit comments

Comments
 (0)