Skip to content

Updating docs and enabling javadocs #2405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion firebase-ml-modeldownloader/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ package com.google.firebase.ml.modeldownloader {
field public static final int MODEL_HASH_MISMATCH = 102; // 0x66
field public static final int NOT_ENOUGH_SPACE = 101; // 0x65
field public static final int NOT_FOUND = 5; // 0x5
field public static final int NO_NETWORK_CONNECTION = 17; // 0x11
field public static final int OUT_OF_RANGE = 11; // 0xb
field public static final int PERMISSION_DENIED = 7; // 0x7
field public static final int RESOURCE_EXHAUSTED = 8; // 0x8
Expand All @@ -51,7 +52,7 @@ package com.google.firebase.ml.modeldownloader {
field public static final int UNKNOWN = 2; // 0x2
}

@IntDef({com.google.firebase.ml.modeldownloader.FirebaseMlException.CANCELLED, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNKNOWN, com.google.firebase.ml.modeldownloader.FirebaseMlException.INVALID_ARGUMENT, com.google.firebase.ml.modeldownloader.FirebaseMlException.DEADLINE_EXCEEDED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_FOUND, com.google.firebase.ml.modeldownloader.FirebaseMlException.ALREADY_EXISTS, com.google.firebase.ml.modeldownloader.FirebaseMlException.PERMISSION_DENIED, com.google.firebase.ml.modeldownloader.FirebaseMlException.RESOURCE_EXHAUSTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.FAILED_PRECONDITION, com.google.firebase.ml.modeldownloader.FirebaseMlException.ABORTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.OUT_OF_RANGE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNIMPLEMENTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.INTERNAL, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAVAILABLE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAUTHENTICATED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_ENOUGH_SPACE, com.google.firebase.ml.modeldownloader.FirebaseMlException.MODEL_HASH_MISMATCH, com.google.firebase.ml.modeldownloader.FirebaseMlException.DOWNLOAD_URL_EXPIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FirebaseMlException.Code {
@IntDef({com.google.firebase.ml.modeldownloader.FirebaseMlException.CANCELLED, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNKNOWN, com.google.firebase.ml.modeldownloader.FirebaseMlException.INVALID_ARGUMENT, com.google.firebase.ml.modeldownloader.FirebaseMlException.DEADLINE_EXCEEDED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_FOUND, com.google.firebase.ml.modeldownloader.FirebaseMlException.ALREADY_EXISTS, com.google.firebase.ml.modeldownloader.FirebaseMlException.PERMISSION_DENIED, com.google.firebase.ml.modeldownloader.FirebaseMlException.RESOURCE_EXHAUSTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.FAILED_PRECONDITION, com.google.firebase.ml.modeldownloader.FirebaseMlException.ABORTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.OUT_OF_RANGE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNIMPLEMENTED, com.google.firebase.ml.modeldownloader.FirebaseMlException.INTERNAL, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAVAILABLE, com.google.firebase.ml.modeldownloader.FirebaseMlException.UNAUTHENTICATED, com.google.firebase.ml.modeldownloader.FirebaseMlException.NO_NETWORK_CONNECTION, com.google.firebase.ml.modeldownloader.FirebaseMlException.NOT_ENOUGH_SPACE, com.google.firebase.ml.modeldownloader.FirebaseMlException.MODEL_HASH_MISMATCH, com.google.firebase.ml.modeldownloader.FirebaseMlException.DOWNLOAD_URL_EXPIRED}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS) public static @interface FirebaseMlException.Code {
}

public class FirebaseModelDownloader {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ plugins {

firebaseLibrary {
testLab.enabled = true
publishJavadoc = false
publishJavadoc = true
}

protobuf {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public class FirebaseMlException extends FirebaseException {
/** The request does not have valid authentication credentials for the operation. */
public static final int UNAUTHENTICATED = 16;

/** There is no network connection. */
public static final int NO_NETWORK_CONNECTION = 17;

// ===============================================================================================
// Error codes: 100 to 149 reserved for errors during model downloading/loading.
/** There is not enough space left on the device. */
Expand Down Expand Up @@ -131,6 +134,7 @@ public class FirebaseMlException extends FirebaseException {
INTERNAL,
UNAVAILABLE,
UNAUTHENTICATED,
NO_NETWORK_CONNECTION,
NOT_ENOUGH_SPACE,
MODEL_HASH_MISMATCH,
DOWNLOAD_URL_EXPIRED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ public static FirebaseModelDownloader getInstance(@NonNull FirebaseApp app) {
* trigger new download, task only completes when download finishes
* </ul>
*
* Most common exceptions include:
*
* <ul>
* <li>{@link FirebaseMlException#NO_NETWORK_CONNECTION}: Error connecting to the network.
* <li>{@link FirebaseMlException#NOT_FOUND}: No model found with the given name.
* <li>{@link FirebaseMlException#NOT_ENOUGH_SPACE}: Not enough space on device to download
* model.
* <li>{@link FirebaseMlException#DOWNLOAD_URL_EXPIRED}: Url used to fetch model expired before
* model download completed. (Rare: these calls are retried internally before being raised.)
* </ul>
*
* @param modelName - model name
* @param downloadType - download type
* @param conditions - download conditions
Expand Down Expand Up @@ -422,11 +433,9 @@ private Task<CustomModel> finishModelDownload(@NonNull String modelName) {
}

/**
* Triggers the move to permanent storage of successful model downloads and lists all models
* downloaded to device.
* Lists all models downloaded to device.
*
* @return The set of all models that are downloaded to this device, triggers completion of file
* moves for completed model downloads.
* @return The set of all models that are downloaded to this device.
*/
@NonNull
public Task<Set<CustomModel>> listDownloadedModels() {
Expand All @@ -440,7 +449,7 @@ public Task<Set<CustomModel>> listDownloadedModels() {
}

/**
* Delete old local models, when no longer in use.
* Delete local model. Removes any information and files associated with the model name.
*
* @param modelName - name of the model
*/
Expand All @@ -463,7 +472,15 @@ private void deleteModelDetails(@NonNull String modelName) {
}

/**
* Update the settings which allow logging to firelog.
* Enables stats collection in Firebase Ml ModelDownloader via Firelog. The stats include API
* calls counts, errors, API call durations, options, etc. No personally identifiable information
* is logged.
*
* <p>The setting is per FirebaseApp, and it is persistent together with app's private data. It
* means if the user uninstalls the app or clears all app data, the setting will be erased. The
* best practice is to set the flag in each initialization.
*
* <p>By default the logging matches the Firebase wide data collection switch.
*
* @param enabled - is statistics logging enabled
*/
Expand All @@ -475,17 +492,15 @@ public void setStatsCollectionEnabled(boolean enabled) {
* Get the current models' download id (returns background download id when applicable). This id
* can be used to create a progress bar to track file download progress.
*
* <p>If no model exists or there is no download in progress, return 0.
*
* <p>If 0 is returned immediately after starting a download via getModel, then
* <p>[Preferred] If getModelTask is not null, then this task returns when the download id is not
* 0 (download has been enqueued) or when the getModelTask completes (returning 0).
*
* <ul>
* <li>the enqueuing wasn't needed: the getModel task already completed and/or no background
* update.
* <li>the enqueuing hasn't completed: the download id hasn't generated yet - try again.
* </ul>
* <p>If getModelTask is null, then immediately returns the download id of the model. This will be
* 0 if the model doesn't exist, the model has completed downloading, or the download hasn't been
* enqueued.
*
* @param modelName - model name
* @param getModelTask - use the most recent getModel task associated with the model name
* @return id associated with Android Download Manager.
*/
@NonNull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,23 +147,23 @@ public Task<CustomModel> getCustomModelDetails(
if (!installationAuthTokenTask.isSuccessful()) {
ErrorCode errorCode = ErrorCode.MODEL_INFO_DOWNLOAD_CONNECTION_FAILED;
String errorMessage = "Failed to get model due to authentication error";
int exceptionCode = FirebaseMlException.UNAUTHENTICATED;
if (installationAuthTokenTask.getException() != null
&& (installationAuthTokenTask.getException() instanceof UnknownHostException
|| installationAuthTokenTask.getException().getCause()
instanceof UnknownHostException)) {
errorCode = ErrorCode.NO_NETWORK_CONNECTION;
errorMessage = "Failed to retrieve model info due to no internet connection.";
exceptionCode = FirebaseMlException.NO_NETWORK_CONNECTION;
}
eventLogger.logDownloadFailureWithReason(
new CustomModel(modelName, modelHash, 0, 0L), false, errorCode.getValue());
return Tasks.forException(
new FirebaseMlException(errorMessage, FirebaseMlException.INTERNAL));
return Tasks.forException(new FirebaseMlException(errorMessage, exceptionCode));
}

connection.setRequestProperty(
INSTALLATIONS_AUTH_TOKEN_HEADER, installationAuthTokenTask.getResult().getToken());
connection.setRequestProperty(API_KEY_HEADER, apiKey);

return fetchDownloadDetails(modelName, connection);
});

Expand Down Expand Up @@ -201,13 +201,12 @@ static long parseTokenExpirationTimestamp(String expiresIn) {
private Task<CustomModel> fetchDownloadDetails(String modelName, HttpURLConnection connection) {
try {
connection.connect();

int httpResponseCode = connection.getResponseCode();
String errorMessage = getErrorStream(connection);

switch (httpResponseCode) {
case HttpURLConnection.HTTP_OK:
return Tasks.forResult(readCustomModelResponse(modelName, connection));
return readCustomModelResponse(modelName, connection);
case HttpURLConnection.HTTP_NOT_MODIFIED:
return Tasks.forResult(null);
case HttpURLConnection.HTTP_NOT_FOUND:
Expand Down Expand Up @@ -256,13 +255,14 @@ private Task<CustomModel> fetchDownloadDetails(String modelName, HttpURLConnecti
} catch (IOException e) {
ErrorCode errorCode = ErrorCode.MODEL_INFO_DOWNLOAD_CONNECTION_FAILED;
String errorMessage = "Failed to get model URL";
int exceptionCode = FirebaseMlException.INTERNAL;
if (e instanceof UnknownHostException) {
errorCode = ErrorCode.NO_NETWORK_CONNECTION;
errorMessage = "Failed to retrieve model info due to no internet connection.";
exceptionCode = FirebaseMlException.NO_NETWORK_CONNECTION;
}
eventLogger.logModelInfoRetrieverFailure(new CustomModel(modelName, "", 0, 0), errorCode);
return Tasks.forException(
new FirebaseMlException(errorMessage, FirebaseMlException.INTERNAL));
return Tasks.forException(new FirebaseMlException(errorMessage, exceptionCode));
}
}

Expand All @@ -275,9 +275,8 @@ private Task<CustomModel> setAndLogException(
return Tasks.forException(new FirebaseMlException(errorMessage, invalidArgument));
}

private CustomModel readCustomModelResponse(
private Task<CustomModel> readCustomModelResponse(
@NonNull String modelName, HttpURLConnection connection) throws IOException {

String encodingKey = connection.getHeaderField(CONTENT_ENCODING_HEADER_KEY);
InputStream inputStream = maybeUnGzip(connection.getInputStream(), encodingKey);
JsonReader reader = new JsonReader(new InputStreamReader(inputStream, UTF_8));
Expand All @@ -288,8 +287,13 @@ private CustomModel readCustomModelResponse(
String modelHash = maybeUnGzipHeader(connection.getHeaderField(ETAG_HEADER), encodingKey);

if (modelHash == null || modelHash.isEmpty()) {
// todo(annz) replace this...
modelHash = connection.getResponseMessage();
eventLogger.logDownloadFailureWithReason(
new CustomModel(modelName, modelHash, 0, 0L),
false,
ErrorCode.MODEL_INFO_DOWNLOAD_CONNECTION_FAILED.getValue());
return Tasks.forException(
new FirebaseMlException(
"Model hash not set in download response.", FirebaseMlException.INTERNAL));
}

// JsonReader.peek will sometimes throw AssertionErrors in Android 8.0 and above. See
Expand Down Expand Up @@ -318,9 +322,10 @@ private CustomModel readCustomModelResponse(
inputStream.close();

if (!downloadUrl.isEmpty() && expireTime > 0L) {
return new CustomModel(modelName, modelHash, fileSize, downloadUrl, expireTime);
return Tasks.forResult(
new CustomModel(modelName, modelHash, fileSize, downloadUrl, expireTime));
}
return null;
return Tasks.forResult(null);
}

private static InputStream maybeUnGzip(InputStream input, String contentEncoding)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,8 @@ public void onReceive(Context context, Intent intent) {
if (downloadingModel == null) {
taskCompletionSource.setException(
new FirebaseMlException(
"No model associated with name: " + modelName,
FirebaseMlException.INVALID_ARGUMENT));
"Possible caching issues: No model associated with name: " + modelName,
FirebaseMlException.INTERNAL));
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,8 @@ public void downloadService_unauthenticatedToken() {

Assert.assertTrue(modelTask.getException() instanceof FirebaseMlException);
Assert.assertEquals(
((FirebaseMlException) modelTask.getException()).getCode(), FirebaseMlException.INTERNAL);
((FirebaseMlException) modelTask.getException()).getCode(),
FirebaseMlException.UNAUTHENTICATED);
Assert.assertTrue(modelTask.getException().getMessage().contains("authentication error"));

verify(mockEventLogger, times(1))
Expand Down Expand Up @@ -472,7 +473,8 @@ public void downloadService_unauthenticatedToken_noNetworkConnection() {

Assert.assertTrue(modelTask.getException() instanceof FirebaseMlException);
Assert.assertEquals(
((FirebaseMlException) modelTask.getException()).getCode(), FirebaseMlException.INTERNAL);
((FirebaseMlException) modelTask.getException()).getCode(),
FirebaseMlException.NO_NETWORK_CONNECTION);
Assert.assertTrue(modelTask.getException().getMessage().contains("no internet connection"));

verify(mockEventLogger, times(1))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ public void ensureModelDownloaded_downloadCompletes_missingModel() throws Except
task.addOnCompleteListener(executor, onCompleteListener);
onCompleteListener.await();
} catch (FirebaseMlException ex) {
assertEquals(ex.getCode(), FirebaseMlException.INVALID_ARGUMENT);
assertEquals(ex.getCode(), FirebaseMlException.INTERNAL);
}
assertTrue(task.isComplete());
assertFalse(task.isSuccessful());
Expand Down