Skip to content

Commit c6f2661

Browse files
committed
Resolve TODOs in SDK
1 parent dfadc97 commit c6f2661

File tree

7 files changed

+88
-51
lines changed

7 files changed

+88
-51
lines changed

firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/FirebaseAppDistribution.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
package com.google.firebase.appdistribution;
1616

1717
import android.net.Uri;
18-
1918
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
2020
import com.google.android.gms.tasks.Task;
2121
import com.google.firebase.FirebaseApp;
2222
import com.google.firebase.appdistribution.internal.FirebaseAppDistributionProxy;
@@ -143,9 +143,41 @@ public interface FirebaseAppDistribution {
143143
*/
144144
void startFeedback(@NonNull CharSequence infoText);
145145

146+
/**
147+
* Starts an activity to collect and submit feedback from the tester, along with the given
148+
* screenshot.
149+
*
150+
* <p>Performs the following actions:
151+
*
152+
* <ol>
153+
* <li>If tester is not signed in, presents the tester with a Google Sign-in UI
154+
* <li>Starts a full screen activity for the tester to compose and submit the feedback
155+
* </ol>
156+
*
157+
* @param infoTextResourceId string resource ID of text to display to the tester before collecting
158+
* feedback data (e.g. Terms and Conditions)
159+
* @param screenshot URI to a bitmap containing a screenshot that will be included with the
160+
* report, or null to not include a screenshot
161+
*/
162+
void startFeedback(@NonNull int infoTextResourceId, @Nullable Uri screenshot);
146163

147-
// TODO: javadoc and infoTextResourceId version
148-
void startFeedback(@NonNull CharSequence infoText, @NonNull Uri screenshotUri);
164+
/**
165+
* Starts an activity to collect and submit feedback from the tester, along with the given
166+
* screenshot.
167+
*
168+
* <p>Performs the following actions:
169+
*
170+
* <ol>
171+
* <li>If tester is not signed in, presents the tester with a Google Sign-in UI
172+
* <li>Starts a full screen activity for the tester to compose and submit the feedback
173+
* </ol>
174+
*
175+
* @param infoText text to display to the tester before collecting feedback data (e.g. Terms and
176+
* Conditions)
177+
* @param screenshot URI to a bitmap containing a screenshot that will be included with the
178+
* report, or null to not include a screenshot
179+
*/
180+
void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screenshotUri);
149181

150182
/** Gets the singleton {@link FirebaseAppDistribution} instance. */
151183
@NonNull

firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/internal/FirebaseAppDistributionProxy.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
package com.google.firebase.appdistribution.internal;
1616

1717
import android.net.Uri;
18-
1918
import androidx.annotation.NonNull;
19+
import androidx.annotation.Nullable;
2020
import com.google.android.gms.tasks.Task;
2121
import com.google.firebase.appdistribution.AppDistributionRelease;
2222
import com.google.firebase.appdistribution.FirebaseAppDistribution;
@@ -85,7 +85,12 @@ public void startFeedback(@NonNull CharSequence infoText) {
8585
}
8686

8787
@Override
88-
public void startFeedback(@NonNull CharSequence infoText, @NonNull Uri screenshotUri) {
88+
public void startFeedback(@NonNull int infoTextResourceId, @Nullable Uri screenshotUri) {
89+
delegate.startFeedback(infoTextResourceId, screenshotUri);
90+
}
91+
92+
@Override
93+
public void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screenshotUri) {
8994
delegate.startFeedback(infoText, screenshotUri);
9095
}
9196
}

firebase-appdistribution-api/src/main/java/com/google/firebase/appdistribution/internal/FirebaseAppDistributionStub.java

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

1717
import android.app.Activity;
1818
import android.net.Uri;
19-
2019
import androidx.annotation.NonNull;
2120
import androidx.annotation.Nullable;
2221
import com.google.android.gms.tasks.Continuation;
@@ -86,7 +85,12 @@ public void startFeedback(@NonNull CharSequence infoText) {
8685
}
8786

8887
@Override
89-
public void startFeedback(@NonNull CharSequence infoText, @NonNull Uri screenshotUri) {
88+
public void startFeedback(@NonNull int infoTextResourceId, @Nullable Uri screenshotUri) {
89+
return;
90+
}
91+
92+
@Override
93+
public void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screenshotUri) {
9094
return;
9195
}
9296

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ private void setupView() {
7272
submitButton.setOnClickListener(this::submitFeedback);
7373

7474
try {
75-
// TODO: set up loading state and wait for screenshot in the background
7675
Bitmap thumbnail = readThumbnail();
7776
ImageView screenshotImageView = this.findViewById(R.id.thumbnail);
7877
screenshotImageView.setImageBitmap(thumbnail);

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

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -318,18 +318,25 @@ public void startFeedback(int infoTextResourceId) {
318318

319319
@Override
320320
public void startFeedback(@NonNull CharSequence infoText) {
321-
// TODO: prevent feedback from starting when another is already in progress. That would allow us
322-
// to remove the de-duping code in the example trigger.
323321
screenshotTaker
324322
.takeScreenshot()
325323
.addOnFailureListener(
326-
taskExecutor, e -> LogWrapper.getInstance().e("Failed to take screenshot", e))
324+
taskExecutor,
325+
e -> {
326+
LogWrapper.getInstance().w("Failed to take screenshot for feedback", e);
327+
startFeedback(infoText, null);
328+
})
327329
.addOnSuccessListener(
328330
taskExecutor, screenshotUri -> startFeedback(infoText, screenshotUri));
329331
}
330332

331333
@Override
332-
public void startFeedback(@NonNull CharSequence infoText, @NonNull Uri screenshotUri) {
334+
public void startFeedback(@NonNull int infoTextResourceId, @Nullable Uri screenshotUri) {
335+
startFeedback(firebaseApp.getApplicationContext().getText(infoTextResourceId), screenshotUri);
336+
}
337+
338+
@Override
339+
public void startFeedback(@NonNull CharSequence infoText, @Nullable Uri screenshotUri) {
333340
testerSignInManager
334341
.signInTester()
335342
.addOnFailureListener(
@@ -346,13 +353,16 @@ public void startFeedback(@NonNull CharSequence infoText, @NonNull Uri screensho
346353
}
347354

348355
private Task<Void> launchFeedbackActivity(
349-
String releaseName, CharSequence infoText, Uri screenshotFilename) {
356+
String releaseName, CharSequence infoText, @Nullable Uri screenshotUri) {
350357
return lifecycleNotifier.consumeForegroundActivity(
351358
activity -> {
359+
LogWrapper.getInstance().i("Launching feedback activity");
352360
Intent intent = new Intent(activity, FeedbackActivity.class);
353361
intent.putExtra(RELEASE_NAME_EXTRA_KEY, releaseName);
354362
intent.putExtra(INFO_TEXT_EXTRA_KEY, infoText);
355-
intent.putExtra(SCREENSHOT_URI_EXTRA_KEY, screenshotFilename.toString());
363+
if (screenshotUri != null) {
364+
intent.putExtra(SCREENSHOT_URI_EXTRA_KEY, screenshotUri.toString());
365+
}
356366
activity.startActivity(intent);
357367
});
358368
}

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

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,10 @@
1818
import android.graphics.Bitmap;
1919
import android.graphics.BitmapFactory;
2020
import android.net.Uri;
21-
import android.util.Log;
2221
import com.google.auto.value.AutoValue;
2322
import com.google.firebase.appdistribution.FirebaseAppDistributionException;
2423
import com.google.firebase.appdistribution.FirebaseAppDistributionException.Status;
25-
import java.io.FileNotFoundException;
24+
import java.io.IOException;
2625
import java.io.InputStream;
2726

2827
public class ImageUtils {
@@ -65,42 +64,25 @@ public static Bitmap readScaledImage(
6564
"Tried to read image with bad dimensions: %dx%d", targetWidth, targetHeight),
6665
Status.UNKNOWN);
6766
}
68-
ImageSize imageSize = ImageSize.read(waitForInputStream(contentResolver, uri));
69-
LogWrapper.getInstance().d("Read screenshot image size: " + imageSize);
7067

68+
// Read the dimensions of the image first
69+
ImageSize imageSize;
70+
try (InputStream inputStream = contentResolver.openInputStream(uri)) {
71+
imageSize = ImageSize.read(inputStream);
72+
LogWrapper.getInstance().d("Read screenshot image size: " + imageSize);
73+
} catch (IOException e) {
74+
throw new FirebaseAppDistributionException(
75+
String.format("Could not read screenshot size from URI %s", uri), Status.UNKNOWN, e);
76+
}
77+
78+
// Read the actual image, scaled using the actual and target dimensions
7179
final BitmapFactory.Options options = new BitmapFactory.Options();
7280
options.inSampleSize =
7381
calculateInSampleSize(imageSize.width(), imageSize.height(), targetWidth, targetHeight);
7482
// Get a fresh input stream because we've exhausted the last one
75-
return BitmapFactory.decodeStream(
76-
waitForInputStream(contentResolver, uri), /* outPadding= */ null, options);
77-
}
78-
79-
private static InputStream waitForInputStream(ContentResolver contentResolver, Uri uri)
80-
throws FirebaseAppDistributionException {
81-
LogWrapper.getInstance().d(TAG, "Trying to read screenshot from URI: " + uri);
82-
for (int i = 0; i < MAX_IMAGE_READ_RETRIES; i++) {
83-
try {
84-
return getInputStream(contentResolver, uri);
85-
} catch (IllegalStateException e) {
86-
Log.d(TAG, "Screenshot at URI is still pending. Sleeping.", e);
87-
try {
88-
Thread.sleep(IMAGE_READ_RETRY_SLEEP_MS);
89-
} catch (InterruptedException ex) {
90-
throw new FirebaseAppDistributionException(
91-
"Interrupted while waiting for screenshot to become available", Status.UNKNOWN);
92-
}
93-
}
94-
}
95-
throw new FirebaseAppDistributionException(
96-
"Timed out waiting for screenshot to be readable.", Status.UNKNOWN);
97-
}
98-
99-
private static InputStream getInputStream(ContentResolver contentResolver, Uri uri)
100-
throws FirebaseAppDistributionException {
101-
try {
102-
return contentResolver.openInputStream(uri);
103-
} catch (FileNotFoundException e) {
83+
try (InputStream inputStream = contentResolver.openInputStream(uri)) {
84+
return BitmapFactory.decodeStream(inputStream, /* outPadding= */ null, options);
85+
} catch (IOException e) {
10486
throw new FirebaseAppDistributionException(
10587
String.format("Could not read screenshot from URI %s", uri), Status.UNKNOWN, e);
10688
}

firebase-appdistribution/test-app/src/main/java/com/googletest/firebase/appdistribution/testapp/FeedbackTriggers.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.database.ContentObserver;
2323
import android.database.Cursor;
2424
import android.net.Uri;
25+
import android.os.Build;
2526
import android.os.Handler;
2627
import android.provider.MediaStore;
2728
import android.provider.MediaStore.Images.Media;
@@ -37,8 +38,13 @@
3738
class FeedbackTriggers extends ContentObserver {
3839

3940
private static final String TAG = "FeedbackTriggers";
41+
private static final boolean SHOULD_CHECK_IF_PENDING = Build.VERSION.SDK_INT == 29;
4042
private static final String[] PROJECTION =
41-
new String[] {MediaStore.Images.Media.DATA, MediaStore.Images.Media._ID};
43+
SHOULD_CHECK_IF_PENDING
44+
? new String[] {MediaStore.Images.Media.DATA}
45+
: new String[] {
46+
MediaStore.Images.Media.DATA, android.provider.MediaStore.MediaColumns.IS_PENDING
47+
};
4248
private final Set<String> seenImages = new HashSet<>();
4349

4450
private final Context context;
@@ -115,12 +121,11 @@ private void maybeStartFeedbackForScreenshot(Uri uri) {
115121
try {
116122
cursor = context.getContentResolver().query(uri, PROJECTION, null, null, null);
117123
if (cursor != null && cursor.moveToFirst()) {
124+
// TODO: check if it's pending
125+
// (http://google3/lens/screenshots/demo/java/com/google/android/lensonscreenshots/ScreenshotDetector.java?l=184)
118126
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
119-
Long id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID));
120127
Log.i(TAG, "Path: " + path);
121128
if (path.toLowerCase().contains("screenshot")) {
122-
// TODO: since we have a file path here, should we just use File or path everywhere
123-
// instead of content URI?
124129
FirebaseAppDistribution.getInstance().startFeedback(infoText, uri);
125130
}
126131
}

0 commit comments

Comments
 (0)