Skip to content

Commit 76673eb

Browse files
authored
Merge branch 'master' into idempotent-requests
2 parents 039d197 + a08c5d1 commit 76673eb

16 files changed

+561
-18
lines changed

CHANGELOG.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
# [4.3.0](https://github.com/parse-community/Parse-SDK-Android/compare/4.2.1...4.3.0) (2024-02-18)
2+
3+
4+
### Features
5+
6+
* Add support for uploading a `ParseFile` from a URI ([#1207](https://github.com/parse-community/Parse-SDK-Android/issues/1207)) ([83aec68](https://github.com/parse-community/Parse-SDK-Android/commit/83aec68cb7f95e0116b3878b8cda099fd3a2e200))
7+
8+
## [4.2.1](https://github.com/parse-community/Parse-SDK-Android/compare/4.2.0...4.2.1) (2023-08-25)
9+
10+
11+
### Bug Fixes
12+
13+
* Missing Proguard rules for R8 in full mode ([#1196](https://github.com/parse-community/Parse-SDK-Android/issues/1196)) ([7db0965](https://github.com/parse-community/Parse-SDK-Android/commit/7db09650447db2e0f82247240ae51687189cd03f))
14+
115
# [4.2.0](https://github.com/parse-community/Parse-SDK-Android/compare/4.1.0...4.2.0) (2023-02-22)
216

317

README.md

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,39 @@ The Parse Android SDK has the following Android API and [Gradle Plugin][gradle-p
4545

4646
## Add Dependency
4747

48-
Add this in your root `build.gradle` file (**not** your module `build.gradle` file):
48+
Add the line `maven { url 'https://www.jitpack.io' }` to your `settings.gradle` file, inside the `repositories` property, for example:
4949

5050
```gradle
51-
allprojects {
51+
dependencyResolutionManagement {
5252
repositories {
53-
...
54-
maven { url "https://jitpack.io" }
53+
maven { url 'https://www.jitpack.io' }
5554
}
5655
}
5756
```
5857

59-
Then, add the library to your project `build.gradle`
58+
Older versions of Android studio require different steps. See the following list of Android Studio versions for alternative instructions. You can find the version of your Android Studio installation by clicking on *Help > About* in the top menu.
59+
60+
<details>
61+
<summary>Arctic Fox | 2020.3.1 or older</summary>
62+
<br>
63+
64+
>
65+
> Add this in your root `build.gradle` file, **not** your module `build.gradle` file:
66+
>
67+
> ```gradle
68+
> allprojects {
69+
> repositories {
70+
> ...
71+
> maven { url "https://jitpack.io" }
72+
> }
73+
> }
74+
> ```
75+
>
76+
> Then, add the library to your project `build.gradle` file.
77+
78+
</details>
79+
80+
Then, add the library to your (module:app) `build.gradle` file, replacing `latest.version.here` with the version of the Parse Android SDK you would like to use. We commend always updating your app to use the [latest release](https://github.com/parse-community/Parse-SDK-Android/releases) version.
6081
6182
```gradle
6283
ext {
@@ -81,8 +102,6 @@ dependencies {
81102
}
82103
```
83104
84-
replacing `latest.version.here` with the latest released version (see JitPack badge above).
85-
86105
## Setup
87106

88107
Initialize Parse in a custom class that extends `Application`:

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version = 4.2.0
1+
version = 4.3.0
22
android.enableJetifier = true
33
android.useAndroidX = true

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-sdk-android",
3-
"version": "4.2.0",
3+
"version": "4.3.0",
44
"repository": {
55
"type": "git",
66
"url": "git+https://github.com/parse-community/Parse-SDK-Android.git"

parse/release-proguard.pro

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1+
-keep @com.parse.ParseClassName class com.parse.*
12
-keepnames class com.parse.** { *; }
3+
-keepclassmembers public class * extends com.parse.** {
4+
public <init>(...);
5+
}
26

37
# Required for Parse
48
-keepattributes *Annotation*
59
-keepattributes Signature
6-
# https://github.com/square/okio#proguard
7-
-dontwarn okio.**
10+
11+
# Retracing stacktraces
12+
-keepattributes LineNumberTable,SourceFile
13+
-renamesourcefileattribute SourceFile
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2015-present, Parse, LLC.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*/
9+
package com.parse;
10+
11+
import android.net.Uri;
12+
import java.io.IOException;
13+
import java.io.InputStream;
14+
import java.io.OutputStream;
15+
16+
class ParseCountingUriHttpBody extends ParseUriHttpBody {
17+
18+
private static final int DEFAULT_CHUNK_SIZE = 4096;
19+
private static final int EOF = -1;
20+
21+
private final ProgressCallback progressCallback;
22+
23+
public ParseCountingUriHttpBody(Uri uri, ProgressCallback progressCallback) {
24+
this(uri, null, progressCallback);
25+
}
26+
27+
public ParseCountingUriHttpBody(
28+
Uri uri, String contentType, ProgressCallback progressCallback) {
29+
super(uri, contentType);
30+
this.progressCallback = progressCallback;
31+
}
32+
33+
@Override
34+
public void writeTo(OutputStream output) throws IOException {
35+
if (output == null) {
36+
throw new IllegalArgumentException("Output stream may not be null");
37+
}
38+
39+
final InputStream fileInput =
40+
Parse.getApplicationContext().getContentResolver().openInputStream(uri);
41+
try {
42+
byte[] buffer = new byte[DEFAULT_CHUNK_SIZE];
43+
int n;
44+
long totalLength = getContentLength();
45+
long position = 0;
46+
while (EOF != (n = fileInput.read(buffer))) {
47+
output.write(buffer, 0, n);
48+
position += n;
49+
50+
if (progressCallback != null) {
51+
int progress = (int) (100 * position / totalLength);
52+
progressCallback.done(progress);
53+
}
54+
}
55+
} finally {
56+
ParseIOUtils.closeQuietly(fileInput);
57+
}
58+
}
59+
}

parse/src/main/java/com/parse/ParseFile.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
package com.parse;
1010

11+
import android.net.Uri;
1112
import android.os.Parcel;
1213
import android.os.Parcelable;
1314
import com.parse.boltsinternal.Continuation;
@@ -64,6 +65,7 @@ public ParseFile[] newArray(int size) {
6465
*/
6566
/* package for tests */ byte[] data;
6667
/* package for tests */ File file;
68+
/* package for tests */ Uri uri;
6769
private State state;
6870

6971
/**
@@ -102,6 +104,21 @@ public ParseFile(String name, byte[] data, String contentType) {
102104
this.data = data;
103105
}
104106

107+
/**
108+
* Creates a new file from a content uri, file name, and content type. Content type will be used
109+
* instead of auto-detection by file extension.
110+
*
111+
* @param name The file's name, ideally with extension. The file name must begin with an
112+
* alphanumeric character, and consist of alphanumeric characters, periods, spaces,
113+
* underscores, or dashes.
114+
* @param uri The file uri.
115+
* @param contentType The file's content type.
116+
*/
117+
public ParseFile(String name, Uri uri, String contentType) {
118+
this(new State.Builder().name(name).mimeType(contentType).build());
119+
this.uri = uri;
120+
}
121+
105122
/**
106123
* Creates a new file from a byte array.
107124
*
@@ -274,6 +291,16 @@ private Task<Void> saveAsync(
274291
progressCallbackOnMainThread(
275292
uploadProgressCallback),
276293
cancellationToken);
294+
} else if (uri != null) {
295+
saveTask =
296+
getFileController()
297+
.saveAsync(
298+
state,
299+
uri,
300+
sessionToken,
301+
progressCallbackOnMainThread(
302+
uploadProgressCallback),
303+
cancellationToken);
277304
} else {
278305
saveTask =
279306
getFileController()

parse/src/main/java/com/parse/ParseFileController.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99
package com.parse;
1010

11+
import android.net.Uri;
1112
import com.parse.boltsinternal.Task;
1213
import com.parse.http.ParseHttpRequest;
1314
import java.io.File;
@@ -163,6 +164,49 @@ public Task<ParseFile.State> saveAsync(
163164
ParseExecutors.io());
164165
}
165166

167+
public Task<ParseFile.State> saveAsync(
168+
final ParseFile.State state,
169+
final Uri uri,
170+
String sessionToken,
171+
ProgressCallback uploadProgressCallback,
172+
Task<Void> cancellationToken) {
173+
if (state.url() != null) { // !isDirty
174+
return Task.forResult(state);
175+
}
176+
if (cancellationToken != null && cancellationToken.isCancelled()) {
177+
return Task.cancelled();
178+
}
179+
180+
final ParseRESTCommand command =
181+
new ParseRESTFileCommand.Builder()
182+
.fileName(state.name())
183+
.uri(uri)
184+
.contentType(state.mimeType())
185+
.sessionToken(sessionToken)
186+
.build();
187+
188+
return command.executeAsync(restClient, uploadProgressCallback, null, cancellationToken)
189+
.onSuccess(
190+
task -> {
191+
JSONObject result = task.getResult();
192+
ParseFile.State newState =
193+
new ParseFile.State.Builder(state)
194+
.name(result.getString("name"))
195+
.url(result.getString("url"))
196+
.build();
197+
198+
// Write data to cache
199+
try {
200+
ParseFileUtils.writeUriToFile(getCacheFile(newState), uri);
201+
} catch (IOException e) {
202+
// do nothing
203+
}
204+
205+
return newState;
206+
},
207+
ParseExecutors.io());
208+
}
209+
166210
public Task<File> fetchAsync(
167211
final ParseFile.State state,
168212
@SuppressWarnings("UnusedParameters") String sessionToken,

parse/src/main/java/com/parse/ParseFileUtils.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package com.parse;
1818

19+
import android.net.Uri;
1920
import androidx.annotation.NonNull;
2021
import java.io.File;
2122
import java.io.FileInputStream;
@@ -115,6 +116,30 @@ public static void writeByteArrayToFile(File file, byte[] data) throws IOExcepti
115116
}
116117
}
117118

119+
/**
120+
* Writes a content uri to a file creating the file if it does not exist.
121+
*
122+
* <p>NOTE: As from v1.3, the parent directories of the file will be created if they do not
123+
* exist.
124+
*
125+
* @param file the file to write to
126+
* @param uri the content uri with data to write to the file
127+
* @throws IOException in case of an I/O error
128+
* @since Commons IO 1.1
129+
*/
130+
public static void writeUriToFile(File file, Uri uri) throws IOException {
131+
OutputStream out = null;
132+
InputStream in = null;
133+
try {
134+
in = Parse.getApplicationContext().getContentResolver().openInputStream(uri);
135+
out = openOutputStream(file);
136+
ParseIOUtils.copyLarge(in, out);
137+
} finally {
138+
ParseIOUtils.closeQuietly(out);
139+
ParseIOUtils.closeQuietly(in);
140+
}
141+
}
142+
118143
// -----------------------------------------------------------------------
119144

120145
/**

0 commit comments

Comments
 (0)