Skip to content

Download module #114

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 5 commits into from
Jul 6, 2020
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
1 change: 1 addition & 0 deletions all/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ dependencies {
api project(path: ':core')
api project(path: ':preprocess')
api project(path: ':ui')
api project(path: ':download')

implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
Expand Down
25 changes: 25 additions & 0 deletions core/src/main/java/com/cloudinary/android/MediaManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.cloudinary.android.callback.UploadCallback;
import com.cloudinary.android.callback.UploadResult;
import com.cloudinary.android.callback.UploadStatus;
import com.cloudinary.android.download.DownloadRequestBuilder;
import com.cloudinary.android.download.DownloadRequestBuilderFactory;
import com.cloudinary.android.payload.ByteArrayPayload;
import com.cloudinary.android.payload.FilePayload;
import com.cloudinary.android.payload.LocalUriPayload;
Expand Down Expand Up @@ -57,6 +59,7 @@ public class MediaManager {
private final ExecutorService executor;

private GlobalUploadPolicy globalUploadPolicy = GlobalUploadPolicy.defaultPolicy();
private DownloadRequestBuilderFactory downloadRequestBuilderFactory;

private MediaManager(@NonNull Context context, @Nullable SignatureProvider signatureProvider, @Nullable Map config) {
executor = new ThreadPoolExecutor(4, 4,
Expand Down Expand Up @@ -442,4 +445,26 @@ SignatureProvider getSignatureProvider() {
void execute(Runnable runnable) {
executor.execute(runnable);
}

/**
* Set a {@link DownloadRequestBuilderFactory} factory that will construct the
* {@link DownloadRequestBuilder} instance, to be used when creating download requests
* using {@link #download(Context)}.
*/
public void setDownloadRequestBuilderFactory(DownloadRequestBuilderFactory factory) {
downloadRequestBuilderFactory = factory;
}

/**
* Create a new {@link DownloadRequestBuilder} to be used to create a download request.
* @param context Android context
* @return The {@link DownloadRequestBuilder} that will create the download request.
*/
public DownloadRequestBuilder download(@NonNull Context context) {
if (downloadRequestBuilderFactory == null) {
throw new IllegalStateException("Must set a factory before downloading.");
}

return downloadRequestBuilderFactory.createDownloadRequestBuilder(context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.cloudinary.android.download;

/**
* Represents an active download request (in progress).
*/
public interface DownloadRequest {

/**
* Cancel the download request.
*/
void cancel();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package com.cloudinary.android.download;

import android.graphics.drawable.Drawable;
import android.widget.ImageView;

import com.cloudinary.Transformation;
import com.cloudinary.android.ResponsiveUrl;

import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;

/**
* Builds a download request.
*/
public interface DownloadRequestBuilder {

/**
* Load the request with a resource id.
* @return Itself for chaining.
*/
DownloadRequestBuilder load(@IdRes int resource);

/**
* Load the request with a String source. The source can either be a remote url, or a cloudinary publicId.
* In the case of a remote url, all cloudinary related builder options will not take place.
* @return Itself for chaining.
*/
DownloadRequestBuilder load(String source);

/**
* Set a {@link Transformation} that will be used to generate the url with.
* Only applies if {@link #load(String)} was called with a cloudinary publicId.
* @return Itself for chaining.
*/
DownloadRequestBuilder transformation(Transformation transformation);

/**
* Set a {@link ResponsiveUrl} that will be used to generate the url with.
* Only applies if {@link #load(String)} was called with a cloudinary publicId.
* @return Itself for chaining
*/
DownloadRequestBuilder responsive(ResponsiveUrl responsiveUrl);

/**
* Set a {@link ResponsiveUrl.Preset} that will be used to generate the url with.
* Only applies if {@link #load(String)} was called with a cloudinary publicId.
* @return Itself for chaining
*/
DownloadRequestBuilder responsive(ResponsiveUrl.Preset responsivePreset);

/**
* Sets an Android resource id for a {@link Drawable} resource to display while a resource is
* loading.
* @param resourceId The id of the resource to use as a placeholder
* @return Itself for chaining.
*/
DownloadRequestBuilder placeholder(@DrawableRes int resourceId);

/**
* Set a callback to be called for the result of the download request.
* @param callback The callback to be called for the result of the download request.
* @return Itself for chaining.
*/
DownloadRequestBuilder callback(DownloadRequestCallback callback);

/**
* Set the target {@link ImageView} to load the resource into and start the operation.
* @param imageView The {@link ImageView} the resource will be loaded into.
* @return The dispatched request.
*/
DownloadRequest into(ImageView imageView);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.cloudinary.android.download;

import android.content.Context;

/**
* Constructs a {@link DownloadRequestBuilder} instance to be used for creating download requests.
*/
public interface DownloadRequestBuilderFactory {

/**
* Create a {@link DownloadRequestBuilder} that will create the download requests.
* @param context Android context.
* @return The created {@link DownloadRequestBuilder}
*/
DownloadRequestBuilder createDownloadRequestBuilder(Context context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.cloudinary.android.download;

/**
* A callback for the result of the download request.
*/
public interface DownloadRequestCallback {

/**
* Called when a request completes successfully.
*/
void onSuccess();

/**
* Called when a request failed.
* @param t The error containing the information about why the request failed.
*/
void onFailure(Throwable t);
}
48 changes: 48 additions & 0 deletions download/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
apply plugin: 'com.android.library'

android {
compileSdkVersion 29
buildToolsVersion "29.0.2"

defaultConfig {
minSdkVersion 14
targetSdkVersion 29
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles 'consumer-rules.pro'
multiDexEnabled true

manifestPlaceholders = [cloudinaryUrl: getCloudinaryUrl() ?: ""]
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

}

dependencies {
implementation project(':core')

compileOnly 'com.squareup.picasso:picasso:2.71828'
compileOnly 'com.facebook.fresco:fresco:2.2.0'
compileOnly 'com.github.bumptech.glide:glide:4.11.0'

testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'org.mockito:mockito-android:2.24.0'
}

ext {
publishArtifactId = 'cloudinary-android-download'
publishArtifactName = 'Cloudinary Android Download Library'
jarFileName = "download"
}

apply from: '../publish.gradle'
14 changes: 14 additions & 0 deletions download/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cloudinary.android.download.test"
android:versionCode="1"
android:versionName="1.0">

<application>
<uses-library android:name="android.test.runner" />
<meta-data
android:name="CLOUDINARY_URL"
android:value="${cloudinaryUrl}" />
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package com.cloudinary.android.download;

import android.content.Context;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.cloudinary.Transformation;
import com.cloudinary.android.MediaManager;
import com.cloudinary.android.ResponsiveUrl;
import com.cloudinary.android.download.test.R;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import androidx.test.platform.app.InstrumentationRegistry;

import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

@RunWith(MockitoJUnitRunner.class)
public class DownloadRequestBuilderImplTest {

private static final String TEST_PUBLIC_ID = "sample";
private static String cloudName;
private static boolean initialized;

private DownloadRequestBuilderImpl sut;

@Mock
private DownloadRequestBuilderStrategy downloadRequestBuilderStrategy;

@Mock
private ImageView imageView;

@BeforeClass
public synchronized static void setup() {
if (!initialized) {
MediaManager.init(InstrumentationRegistry.getInstrumentation().getTargetContext());
cloudName = MediaManager.get().getCloudinary().config.cloudName;
initialized = true;
}
}

@Before
public void initSut() {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
sut = new DownloadRequestBuilderImpl(context, downloadRequestBuilderStrategy);
}

@Test
public void testLoadResource() {
int resource = R.drawable.old_logo;

sut.load(resource);
sut.into(imageView);

verify(downloadRequestBuilderStrategy, times(1)).load(eq(resource));
verify(downloadRequestBuilderStrategy, times(1)).into(imageView);
}

@Test
public void testLoadWithRemoteUrl() {
String remoteUrl = String.format("https://res.cloudinary.com/%s/image/upload/%s", cloudName, TEST_PUBLIC_ID);

sut.load(remoteUrl);
sut.into(imageView);

verify(downloadRequestBuilderStrategy, times(1)).load(eq(remoteUrl));
verify(downloadRequestBuilderStrategy, times(1)).into(imageView);
}

@Test
public void testLoadWithGeneratedCloudinaryUrlSource() {
sut.load(TEST_PUBLIC_ID);
sut.into(imageView);

String expectedUrl = String.format("https://res.cloudinary.com/%s/image/upload/%s", cloudName, TEST_PUBLIC_ID);
verify(downloadRequestBuilderStrategy, times(1)).load(eq(expectedUrl));
verify(downloadRequestBuilderStrategy, times(1)).into(imageView);
}

@Test
public void testLoadWithGeneratedCloudinaryUrlSourceWithTransformation() {
sut.load(TEST_PUBLIC_ID);
sut.transformation(new Transformation().width(200).height(400));
sut.into(imageView);

String expectedUrl = String.format("https://res.cloudinary.com/%s/image/upload/h_400,w_200/%s", cloudName, TEST_PUBLIC_ID);
verify(downloadRequestBuilderStrategy, times(1)).load(eq(expectedUrl));
verify(downloadRequestBuilderStrategy, times(1)).into(imageView);
}

@Test
public void testLoadWithResponsive() {
Context context = InstrumentationRegistry.getInstrumentation().getContext();
LinearLayout linearLayout = new LinearLayout(context);
ImageView imageView = new ImageView(context);
int width = 200;
int height = 400;
linearLayout.layout(0, 0, width, height);
imageView.layout(0, 0, width, height);
linearLayout.addView(imageView);

sut.load(TEST_PUBLIC_ID);
sut.responsive(ResponsiveUrl.Preset.AUTO_FILL);
sut.into(imageView);

String expectedUrl = String.format("https://res.cloudinary.com/%s/image/upload/c_fill,g_auto,h_%d,w_%d/%s", cloudName, height, width, TEST_PUBLIC_ID);
verify(downloadRequestBuilderStrategy, times(1)).load(eq(expectedUrl));
verify(downloadRequestBuilderStrategy, times(1)).into(imageView);
}

@Test
public void testRequestBuiltWithPlaceholder() {
int placeholder = R.drawable.old_logo;

sut.load(TEST_PUBLIC_ID);
sut.placeholder(placeholder);
sut.into(imageView);

verify(downloadRequestBuilderStrategy, times(1)).placeholder(eq(placeholder));
verify(downloadRequestBuilderStrategy, times(1)).into(imageView);
}
}
Loading