diff --git a/CHANGELOG.md b/CHANGELOG.md index f90b4435b..acb422ae1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # App Center SDK for Android Change Log +## Version 5.0.2 (In development) + +### AppCenter + +* **[Improvement]** Support updates using AAB file uploaded to the portal. +* **[Fix]** Fix SDK crash if the `ConnectivityManager.getNetworkInfo` method call throws an exception. + ## Version 5.0.1 ### AppCenter diff --git a/sdk/appcenter-distribute/src/androidTest/java/com/microsoft/appcenter/distribute/ReleaseDetailsTest.java b/sdk/appcenter-distribute/src/androidTest/java/com/microsoft/appcenter/distribute/ReleaseDetailsTest.java index b2944955d..1c719ca7a 100644 --- a/sdk/appcenter-distribute/src/androidTest/java/com/microsoft/appcenter/distribute/ReleaseDetailsTest.java +++ b/sdk/appcenter-distribute/src/androidTest/java/com/microsoft/appcenter/distribute/ReleaseDetailsTest.java @@ -31,6 +31,7 @@ public void parse() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -46,6 +47,7 @@ public void parse() throws JSONException { assertFalse(releaseDetails.isMandatoryUpdate()); assertEquals("9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60", releaseDetails.getReleaseHash()); assertEquals("fd37a4b1-4937-45ef-97fb-b864154371f0", releaseDetails.getDistributionGroupId()); + assertEquals(FileExtension.apk, releaseDetails.getFileExtension()); } @Test(expected = JSONException.class) @@ -59,6 +61,7 @@ public void missingId() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -76,6 +79,7 @@ public void invalidId() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -93,6 +97,7 @@ public void acceptIdAsString() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -119,6 +124,7 @@ public void missingVersion() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -136,6 +142,7 @@ public void invalidVersion() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -152,6 +159,7 @@ public void missingShortVersion() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -168,6 +176,7 @@ public void missingReleaseNotes() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -195,6 +204,7 @@ public void nullReleaseNotes() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -224,6 +234,7 @@ public void nullReleaseNotesUrl() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -250,6 +261,7 @@ public void missingApiLevel() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -267,6 +279,7 @@ public void acceptApiLevelAsString() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -294,6 +307,7 @@ public void invalidApiLevel() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -310,6 +324,7 @@ public void missingDownloadUrl() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -327,6 +342,7 @@ public void missingDownloadUrlScheme() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -344,6 +360,7 @@ public void invalidDownloadUrlScheme() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -360,6 +377,7 @@ public void missingSize() throws JSONException { "download_url: 'http://download.thinkbroadband.com/1GB.zip'," + "mandatory_update: false," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -377,6 +395,7 @@ public void mandatoryUpdate() throws JSONException { "size: 4242," + "mandatory_update: true," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); @@ -403,6 +422,7 @@ public void missingMandatoryUpdate() throws JSONException { "size: 4242," + "download_url: 'http://download.thinkbroadband.com/1GB.zip'," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -436,6 +456,7 @@ public void emptyPackageHashes() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: []," + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -453,6 +474,7 @@ public void invalidPackageHashes() throws JSONException { "size: 4242," + "mandatory_update: false," + "package_hashes: '9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60'" + + "fileExtension: 'apk'," + "distribution_group_id: 'fd37a4b1-4937-45ef-97fb-b864154371f0'" + "}"; ReleaseDetails.parse(json); @@ -470,6 +492,7 @@ public void nullDistributionGroupId() throws JSONException { "download_url: 'http://download.thinkbroadband.com/1GB.zip'," + "size: 4242," + "mandatory_update: false," + + "fileExtension: 'apk'," + "package_hashes: ['9f52199c986d9210842824df695900e1656180946212bd5e8978501a5b732e60']" + "}"; ReleaseDetails releaseDetails = ReleaseDetails.parse(json); diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/DistributeConstants.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/DistributeConstants.java index aeaf14c9b..4a68eed33 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/DistributeConstants.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/DistributeConstants.java @@ -77,14 +77,16 @@ public final class DistributeConstants { static final String PRIVATE_UPDATE_SETUP_PATH_FORMAT = "/apps/%s/private-update-setup/"; /** - * Check latest private release API URL path. Contains variables: appSecret, release_hash, extra query string parameters. + * Check latest private release API URL path. Contains variables: is_install_page, appSecret, release_hash, extra query string parameters. + * is_install_page - API parameter for downloading the update apk file, even if an aab file was uploaded. */ - static final String GET_LATEST_PRIVATE_RELEASE_PATH_FORMAT = "/sdk/apps/%s/releases/private/latest?release_hash=%s%s"; + static final String GET_LATEST_PRIVATE_RELEASE_PATH_FORMAT = "/sdk/apps/%s/releases/private/latest?is_install_page=true&release_hash=%s%s"; /** - * Check latest public release API URL path. Contains variables: appSecret, release_hash, extra query string parameters. + * Check latest public release API URL path. Contains variables: is_install_page, appSecret, release_hash, extra query string parameters. + * is_install_page - API parameter for downloading the update apk file, even if an aab file was uploaded. */ - static final String GET_LATEST_PUBLIC_RELEASE_PATH_FORMAT = "/public/sdk/apps/%s/releases/latest?release_hash=%s%s"; + static final String GET_LATEST_PUBLIC_RELEASE_PATH_FORMAT = "/public/sdk/apps/%s/releases/latest?is_install_page=true&release_hash=%s%s"; /** * API parameter for release hash. diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/FileExtension.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/FileExtension.java new file mode 100644 index 000000000..f833482f8 --- /dev/null +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/FileExtension.java @@ -0,0 +1,6 @@ +package com.microsoft.appcenter.distribute; + +public enum FileExtension { + aab, + apk +} diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/ReleaseDetails.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/ReleaseDetails.java index dd02057ef..73ad83fda 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/ReleaseDetails.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/ReleaseDetails.java @@ -32,6 +32,8 @@ public class ReleaseDetails { private static final String MIN_API_LEVEL = "android_min_api_level"; + private static final String FILE_EXTENSION = "fileExtension"; + private static final String DOWNLOAD_URL = "download_url"; private static final String MANDATORY_UPDATE = "mandatory_update"; @@ -79,6 +81,11 @@ public class ReleaseDetails { */ private int minApiLevel; + /** + * The original update file extension. + */ + private FileExtension fileExtension; + /** * The URL that hosts the binary for this release. */ @@ -117,6 +124,7 @@ static ReleaseDetails parse(String json) throws JSONException { releaseDetails.releaseNotes = object.isNull(RELEASE_NOTES) ? null : object.getString(RELEASE_NOTES); releaseDetails.releaseNotesUrl = object.isNull(RELEASE_NOTES_URL) ? null : Uri.parse(object.getString(RELEASE_NOTES_URL)); releaseDetails.minApiLevel = object.getInt(MIN_API_LEVEL); + releaseDetails.fileExtension = FileExtension.valueOf(object.getString(FILE_EXTENSION)); releaseDetails.downloadUrl = Uri.parse(object.getString(DOWNLOAD_URL)); String scheme = releaseDetails.downloadUrl.getScheme(); if (scheme == null || !scheme.startsWith("http")) { @@ -195,6 +203,15 @@ int getMinApiLevel() { return minApiLevel; } + /** + * Get The original update file extension value. + * + * @return the FileExtension value. + */ + public FileExtension getFileExtension() { + return fileExtension; + } + /** * Get the downloadUrl value. * diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloader.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloader.java index 3083d1fd4..61dbd50ac 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloader.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloader.java @@ -23,6 +23,7 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; +import com.microsoft.appcenter.distribute.FileExtension; import com.microsoft.appcenter.distribute.R; import com.microsoft.appcenter.distribute.ReleaseDetails; import com.microsoft.appcenter.distribute.download.AbstractReleaseDownloader; @@ -249,6 +250,11 @@ synchronized void onDownloadError(RuntimeException e) { } private boolean isDownloadedFileValid() { + // As per the current system design, only the files with APK + // extension have their size correctly indicated in the release details. + if (mReleaseDetails.getFileExtension() != FileExtension.apk) { + return true; + } try (ParcelFileDescriptor fileDescriptor = getDownloadManager().openDownloadedFile(mDownloadId)) { return fileDescriptor.getStatSize() == mReleaseDetails.getSize(); } catch (IOException e) { diff --git a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/install/session/SessionReleaseInstaller.java b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/install/session/SessionReleaseInstaller.java index e1634c05a..c855c63b7 100644 --- a/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/install/session/SessionReleaseInstaller.java +++ b/sdk/appcenter-distribute/src/main/java/com/microsoft/appcenter/distribute/install/session/SessionReleaseInstaller.java @@ -187,6 +187,7 @@ public void run() { /* Cancels installation if this flag hasn't been reset by progress event. */ if (mUserConfirmationRequested) { + AppCenterLog.error(LOG_TAG, "Canceling installation due to lack of progress."); onCancel(); } } diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java index d2bb94a70..9e83a5b64 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/DistributeBeforeApiSuccessTest.java @@ -1284,7 +1284,7 @@ public void willNotReportReleaseInstallForPrivateGroupWithoutStoredReleaseHash() Distribute.setUpdateTrack(UpdateTrack.PRIVATE); start(); Distribute.getInstance().onActivityResumed(mActivity); - verify(mHttpClient).callAsync(matches("^https://.*?/sdk/apps/a/releases/private/latest\\?release_hash=" + TEST_HASH + "$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); + verify(mHttpClient).callAsync(matches("^https://.*?/sdk/apps/a/releases/private/latest\\?is_install_page=true&release_hash=" + TEST_HASH + "$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); } @Test @@ -1301,7 +1301,7 @@ public void willNotReportReleaseInstallForPrivateGroupWhenReleaseHashesDoNotMatc Distribute.setUpdateTrack(UpdateTrack.PRIVATE); start(); Distribute.getInstance().onActivityResumed(mActivity); - verify(mHttpClient).callAsync(matches("^https://.*?/sdk/apps/a/releases/private/latest\\?release_hash=" + TEST_HASH + "$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); + verify(mHttpClient).callAsync(matches("^https://.*?/sdk/apps/a/releases/private/latest\\?is_install_page=true&release_hash=" + TEST_HASH + "$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); } @Test @@ -1320,7 +1320,7 @@ public void reportReleaseInstallForPrivateGroupWhenReleaseHashesMatch() { Distribute.setUpdateTrack(UpdateTrack.PRIVATE); start(); Distribute.getInstance().onActivityResumed(mActivity); - verify(mHttpClient).callAsync(matches("^https://.*?/sdk/apps/a/releases/private/latest\\?release_hash=" + TEST_HASH + "&distribution_group_id=" + distributionGroupId + "&downloaded_release_id=4$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); + verify(mHttpClient).callAsync(matches("^https://.*?/sdk/apps/a/releases/private/latest\\?is_install_page=true&release_hash=" + TEST_HASH + "&distribution_group_id=" + distributionGroupId + "&downloaded_release_id=4$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); } @Test @@ -1337,7 +1337,7 @@ public void reportReleaseInstallForPublicGroupWhenReleaseHashesMatch() { /* Primary storage will be missing data. */ start(); Distribute.getInstance().onActivityResumed(mActivity); - verify(mHttpClient).callAsync(matches("^https://.*?/public/sdk/apps/a/releases/latest\\?release_hash=" + TEST_HASH + "&install_id=" + mInstallId + "&distribution_group_id=" + distributionGroupId + "&downloaded_release_id=4$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); + verify(mHttpClient).callAsync(matches("^https://.*?/public/sdk/apps/a/releases/latest\\?is_install_page=true&release_hash=" + TEST_HASH + "&install_id=" + mInstallId + "&distribution_group_id=" + distributionGroupId + "&downloaded_release_id=4$"), eq("GET"), eq(headers), any(HttpClient.CallTemplate.class), any(ServiceCallback.class)); } @Test diff --git a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloaderTest.java b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloaderTest.java index 3a57551ef..dd7fba963 100644 --- a/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloaderTest.java +++ b/sdk/appcenter-distribute/src/test/java/com/microsoft/appcenter/distribute/download/manager/DownloadManagerReleaseDownloaderTest.java @@ -34,6 +34,7 @@ import android.os.Handler; import android.os.ParcelFileDescriptor; +import com.microsoft.appcenter.distribute.FileExtension; import com.microsoft.appcenter.distribute.ReleaseDetails; import com.microsoft.appcenter.distribute.download.ReleaseDownloader; import com.microsoft.appcenter.utils.AsyncTaskUtils; @@ -405,6 +406,8 @@ public void doNotOnDownloadProgressAfterCancellation() { @Test public void completeDownload() throws IOException { + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.apk); /* Complete download. */ mReleaseDownloader.onDownloadComplete(); @@ -438,6 +441,8 @@ public void errorDownload() { @Test public void errorOnOpenDownloadedFile() throws IOException { + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.apk); /* Throw exception. */ when(mDownloadManager.openDownloadedFile(anyLong())).thenThrow(new FileNotFoundException()); @@ -449,12 +454,30 @@ public void errorOnOpenDownloadedFile() throws IOException { verify(mListener).onError(anyString()); } + @Test + public void errorOnCloseFileDescriptor() throws IOException { + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.apk); + + /* Throw exception. */ + doThrow(new IOException()).when(mFileDescriptor).close(); + + /* Complete download. */ + mReleaseDownloader.onDownloadComplete(); + + /* Verify. */ + verify(mListener).onError(anyString()); + } + @Test public void errorOnInvalidFile() throws IOException { /* If size is different. */ when(mReleaseDetails.getSize()).thenReturn(142 * 1024L); + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.apk); + /* Complete download. */ mReleaseDownloader.onDownloadComplete(); @@ -464,31 +487,47 @@ public void errorOnInvalidFile() throws IOException { } @Test - public void errorDownloadFileNotFound() throws IOException { + public void sizeOfApkIsCorrect() { + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.apk); - /* DownloadManager returns null. */ - when(mDownloadManager.getUriForDownloadedFile(anyLong())).thenReturn(null); + /* Complete download. */ + mReleaseDownloader.onDownloadComplete(); + + /* Verify. */ + verify(mFileDescriptor).getStatSize(); + verify(mListener, times(0)).onError(anyString()); + } + + @Test + public void ignoreFileSizeComparisonForApkTransformedFromAab() { + /* If size is different. */ + when(mReleaseDetails.getSize()).thenReturn(142 * 1024L); + + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.aab); /* Complete download. */ mReleaseDownloader.onDownloadComplete(); /* Verify. */ - verify(mFileDescriptor).close(); - verify(mListener).onError(anyString()); + verify(mFileDescriptor, times(0)).getStatSize(); + verify(mListener, times(0)).onError(anyString()); } @Test - public void exceptionOnClosingFileDescriptor() throws IOException { + public void errorDownloadFileNotFound() throws IOException { + /* Define file extension. */ + when(mReleaseDetails.getFileExtension()).thenReturn(FileExtension.apk); - /* Throw exception in invalid size callback. */ - doThrow(new IOException()).when(mFileDescriptor).close(); + /* DownloadManager returns null. */ + when(mDownloadManager.getUriForDownloadedFile(anyLong())).thenReturn(null); /* Complete download. */ mReleaseDownloader.onDownloadComplete(); /* Verify. */ verify(mFileDescriptor).close(); - verify(mListener, never()).onComplete(any(Uri.class)); verify(mListener).onError(anyString()); } diff --git a/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/NetworkStateHelper.java b/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/NetworkStateHelper.java index ce4c86d28..fed8273c2 100644 --- a/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/NetworkStateHelper.java +++ b/sdk/appcenter/src/main/java/com/microsoft/appcenter/utils/NetworkStateHelper.java @@ -143,9 +143,13 @@ private boolean isAnyNetworkConnected() { return false; } for (Network network : networks) { - NetworkInfo info = mConnectivityManager.getNetworkInfo(network); - if (info != null && info.isConnected()) { - return true; + try { + NetworkInfo info = mConnectivityManager.getNetworkInfo(network); + if (info != null && info.isConnected()) { + return true; + } + } catch (RuntimeException e) { + AppCenterLog.warn(LOG_TAG, "Failed to get network info", e); } } return false; diff --git a/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/NetworkStateHelperTestFromLollipop.java b/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/NetworkStateHelperTestFromLollipop.java index 4bab1a20a..225f56c07 100644 --- a/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/NetworkStateHelperTestFromLollipop.java +++ b/sdk/appcenter/src/test/java/com/microsoft/appcenter/utils/NetworkStateHelperTestFromLollipop.java @@ -14,6 +14,7 @@ import android.net.NetworkRequest; import android.os.Build; +import com.microsoft.appcenter.AppCenter; import com.microsoft.appcenter.test.TestUtils; import org.junit.After; @@ -26,6 +27,8 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -34,14 +37,19 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.verifyStatic; import static org.powermock.api.mockito.PowerMockito.whenNew; -@PrepareForTest(NetworkStateHelper.class) +@PrepareForTest({NetworkStateHelper.class, AppCenterLog.class}) public class NetworkStateHelperTestFromLollipop extends AbstractNetworkStateHelperTest { @Before public void setUp() throws Exception { TestUtils.setInternalState(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.LOLLIPOP); + + /* Mock static classes. */ + mockStatic(AppCenterLog.class); } @After @@ -178,4 +186,15 @@ public void verifyRequestedCapabilitiesFromAndroidM() throws Exception { verify(builder).addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); verify(builder, never()).addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); } + + @Test + public void verifyNullPointerExceptionCatch() { + NetworkStateHelper helper = new NetworkStateHelper(mContext); + Network network = mock(Network.class); + when(mConnectivityManager.getAllNetworks()).thenReturn(new Network[] { network }); + when(mConnectivityManager.getNetworkInfo(any())).thenThrow(new NullPointerException()); + assertFalse(helper.isNetworkConnected()); + verifyStatic(AppCenterLog.class); + AppCenterLog.warn(eq(AppCenter.LOG_TAG), anyString(), any(RuntimeException.class)); + } } diff --git a/versions.gradle b/versions.gradle index cd89f3ba7..b1d7f3baa 100644 --- a/versions.gradle +++ b/versions.gradle @@ -6,8 +6,8 @@ // Version constants ext { - versionCode = 70 - versionName = '5.0.1' + versionCode = 71 + versionName = '5.0.2' minSdkVersion = 21 compileSdkVersion = 33 targetSdkVersion = 33