Skip to content

Commit 7f30aea

Browse files
committed
Merge branch 'master' of github.com:firebase/firebase-android-sdk into floc-master
2 parents 0990fee + 75d0130 commit 7f30aea

File tree

18 files changed

+1511
-178
lines changed

18 files changed

+1511
-178
lines changed

firebase-common/src/main/AndroidManifest.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest
33
xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:tools="http://schemas.android.com/tools"
45
package="com.google.firebase">
56
<!--Although the *SdkVersion is captured in gradle build files, this is required for non gradle builds-->
67
<!--<uses-sdk android:minSdkVersion="14"/>-->
78
<application>
89

10+
<service android:name="com.google.firebase.components.ComponentDiscoveryService"
11+
android:directBootAware="true" android:exported="false"
12+
tools:targetApi="n" />
13+
914
<provider
1015
android:name="com.google.firebase.provider.FirebaseInitProvider"
1116
android:authorities="${applicationId}.firebaseinitprovider"

firebase-config/src/main/java/com/google/firebase/remoteconfig/RemoteConfigComponent.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public class RemoteConfigComponent {
6060
/** Name of the file where defaults configs are stored. */
6161
public static final String DEFAULTS_FILE_NAME = "defaults";
6262
/** Timeout for the call to the Firebase Remote Config servers in second. */
63-
public static final long NETWORK_CONNECTION_TIMEOUT_IN_SECONDS = 5;
63+
public static final long NETWORK_CONNECTION_TIMEOUT_IN_SECONDS = 60;
6464

6565
private static final String FIREBASE_REMOTE_CONFIG_FILE_NAME_PREFIX = "frc";
6666
private static final String PREFERENCES_FILE_NAME = "settings";

firebase-database/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# 19.1.0
2+
- [feature] Added support for the Firebase Database Emulator. To connect to
3+
the emulator, specify "http://<emulatorHost>/?ns=<projectId>" as your
4+
Database URL (via `FirebaseDatabase.getInstance(String)`).
5+
Note that if you are running the Database Emulator on "localhost" and
6+
connecting from an app that is running inside an Android Emulator, the
7+
emulator host will be "10.0.2.2" followed by its port.
8+
19
# 18.0.1
210
- [changed] The SDK now reports the correct version number (via
311
`FirebaseDatabase.getSdkVersion()`).

firebase-database/src/androidTest/java/com/google/firebase/database/DataTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1081,9 +1081,9 @@ public void urlEncodingAndDecodingWorks()
10811081
new DatabaseReference(
10821082
IntegrationTestValues.getNamespace() + "/a%b&c@d/space: /non-ascii:ø", ctx);
10831083
String result = ref.toString();
1084-
String expected =
1084+
String encoded =
10851085
IntegrationTestValues.getNamespace() + "/a%25b%26c%40d/space%3A%20/non-ascii%3A%C3%B8";
1086-
assertEquals(expected, result);
1086+
assertEquals(encoded, result);
10871087

10881088
String child = "" + new Random().nextInt(100000000);
10891089
new WriteFuture(ref.child(child), "testdata").timedGet();

firebase-database/src/androidTest/java/com/google/firebase/database/FirebaseDatabaseTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public void persistenceSettings() {
170170
config.setPersistenceCacheSizeBytes(1 * 1024 * 1024);
171171

172172
try {
173-
FirebaseDatabase db = new DatabaseReference("", config).getDatabase();
173+
FirebaseDatabase db = new DatabaseReference("http://localhost", config).getDatabase();
174174
db.setPersistenceCacheSizeBytes(1 * 1024 * 1024);
175175
fail("should throw - can't modify after init");
176176
} catch (DatabaseException e) {

firebase-database/src/androidTest/java/com/google/firebase/database/RealtimeTest.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
import androidx.test.runner.AndroidJUnit4;
2424
import com.google.firebase.database.core.DatabaseConfig;
2525
import com.google.firebase.database.core.RepoManager;
26-
import com.google.firebase.database.core.utilities.ParsedUrl;
27-
import com.google.firebase.database.core.utilities.Utilities;
2826
import com.google.firebase.database.future.ReadFuture;
2927
import com.google.firebase.database.future.WriteFuture;
3028
import java.util.List;
@@ -48,21 +46,6 @@ public void tearDown() {
4846
IntegrationTestHelpers.failOnFirstUncaughtException();
4947
}
5048

51-
@Test
52-
public void testUrlParsing() throws DatabaseException {
53-
ParsedUrl parsed = Utilities.parseUrl("http://gsoltis.fblocal.com:9000");
54-
assertEquals(parsed.path.toString(), "/");
55-
assertEquals(parsed.repoInfo.host, "gsoltis.fblocal.com:9000");
56-
assertEquals(parsed.repoInfo.internalHost, "gsoltis.fblocal.com:9000");
57-
assertEquals(parsed.repoInfo.secure, false);
58-
59-
parsed = Utilities.parseUrl("http://gsoltis.firebaseio.com/foo/bar");
60-
assertEquals(parsed.path.toString(), "/foo/bar");
61-
assertEquals(parsed.repoInfo.host, "gsoltis.firebaseio.com");
62-
assertEquals(parsed.repoInfo.internalHost, "gsoltis.firebaseio.com");
63-
assertEquals(parsed.repoInfo.secure, true);
64-
}
65-
6649
@Test
6750
public void testOnDisconnectSetWorks()
6851
throws DatabaseException, TestFailure, TimeoutException, InterruptedException {

firebase-database/src/main/java/com/google/firebase/database/core/utilities/DefaultRunLoop.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,20 @@ public static String messageForException(Throwable t) {
128128
+ "https://firebase.google.com/docs/database/ios/structure-data#best_practices_for_data_structure"
129129
+ " and "
130130
+ "https://firebase.google.com/docs/database/android/retrieve-data#filtering_data";
131+
} else if (t instanceof NoClassDefFoundError) {
132+
return "A symbol that the Firebase Database SDK depends on failed to load. This usually "
133+
+ "indicates that your project includes an incompatible version of another Firebase "
134+
+ "dependency. If updating your dependencies to the latest version does not resolve "
135+
+ "this issue, please file a report at https://github.com/firebase/firebase-android-sdk";
131136
} else if (t instanceof DatabaseException) {
132137
// Exception should be self-explanatory and they shouldn't contact support.
133138
return "";
134139
} else {
135140
return "Uncaught exception in Firebase Database runloop ("
136141
+ FirebaseDatabase.getSdkVersion()
137-
+ "). Please report to [email protected]";
142+
+ "). If you are not already on the latest version of the Firebase SDKs, try updating "
143+
+ "your dependencies. Should this problem persist, please file a report at "
144+
+ "https://github.com/firebase/firebase-android-sdk";
138145
}
139146
}
140147
}

firebase-database/src/main/java/com/google/firebase/database/core/utilities/ParsedUrl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,15 @@ public class ParsedUrl {
2121

2222
public RepoInfo repoInfo;
2323
public Path path;
24+
25+
@Override
26+
public boolean equals(Object o) {
27+
if (this == o) return true;
28+
if (o == null || getClass() != o.getClass()) return false;
29+
30+
ParsedUrl parsedUrl = (ParsedUrl) o;
31+
32+
if (!repoInfo.equals(parsedUrl.repoInfo)) return false;
33+
return path.equals(parsedUrl.path);
34+
}
2435
}

firebase-database/src/main/java/com/google/firebase/database/core/utilities/Utilities.java

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
package com.google.firebase.database.core.utilities;
1616

17+
import android.net.Uri;
1718
import android.util.Base64;
1819
import com.google.android.gms.tasks.Task;
1920
import com.google.android.gms.tasks.TaskCompletionSource;
@@ -23,83 +24,85 @@
2324
import com.google.firebase.database.core.Path;
2425
import com.google.firebase.database.core.RepoInfo;
2526
import java.io.UnsupportedEncodingException;
26-
import java.net.URI;
27-
import java.net.URISyntaxException;
28-
import java.net.URLEncoder;
2927
import java.security.MessageDigest;
3028
import java.security.NoSuchAlgorithmException;
31-
import java.util.ArrayList;
3229
import java.util.Map;
3330

3431
public class Utilities {
3532
private static final char[] HEX_CHARACTERS = "0123456789abcdef".toCharArray();
3633

3734
public static ParsedUrl parseUrl(String url) throws DatabaseException {
38-
String original = url;
3935
try {
40-
int schemeOffset = original.indexOf("//");
41-
if (schemeOffset == -1) {
42-
throw new URISyntaxException(original, "Invalid scheme specified");
43-
}
44-
int pathOffset = original.substring(schemeOffset + 2).indexOf("/");
45-
if (pathOffset != -1) {
46-
pathOffset += schemeOffset + 2;
47-
String[] pathSegments = original.substring(pathOffset).split("/", -1);
48-
StringBuilder builder = new StringBuilder();
49-
for (int i = 0; i < pathSegments.length; ++i) {
50-
if (!pathSegments[i].equals("")) {
51-
builder.append("/");
52-
builder.append(URLEncoder.encode(pathSegments[i], "UTF-8"));
53-
}
54-
}
55-
original = original.substring(0, pathOffset) + builder.toString();
56-
}
36+
Uri uri = Uri.parse(url);
5737

58-
URI uri = new URI(original);
59-
// URLEncoding a space turns it into a '+', which is different
60-
// from our expected behavior. Do a manual replace to fix it.
61-
String pathString = uri.getPath().replace("+", " ");
62-
Validation.validateRootPathString(pathString);
63-
Path path = new Path(pathString);
6438
String scheme = uri.getScheme();
39+
if (scheme == null) {
40+
throw new IllegalArgumentException("Database URL does not specify a URL scheme");
41+
}
42+
43+
String host = uri.getHost();
44+
if (host == null) {
45+
throw new IllegalArgumentException("Database URL does not specify a valid host");
46+
}
6547

6648
RepoInfo repoInfo = new RepoInfo();
67-
repoInfo.host = uri.getHost().toLowerCase();
49+
repoInfo.host = host.toLowerCase();
6850

6951
int port = uri.getPort();
7052
if (port != -1) {
71-
repoInfo.secure = scheme.equals("https");
53+
repoInfo.secure = scheme.equals("https") || scheme.equals("wss");
7254
repoInfo.host += ":" + port;
7355
} else {
7456
repoInfo.secure = true;
7557
}
76-
String[] parts = repoInfo.host.split("\\.", -1);
7758

78-
repoInfo.namespace = parts[0].toLowerCase();
59+
String namespaceParam = uri.getQueryParameter("ns");
60+
if (namespaceParam != null) {
61+
repoInfo.namespace = namespaceParam;
62+
} else {
63+
String[] parts = host.split("\\.", -1);
64+
repoInfo.namespace = parts[0].toLowerCase();
65+
}
66+
7967
repoInfo.internalHost = repoInfo.host;
68+
69+
String originalPathString = extractPathString(url);
70+
// URLEncoding a space turns it into a '+', which is different
71+
// from our expected behavior. Do a manual replace to fix it.
72+
originalPathString = originalPathString.replace("+", " ");
73+
Validation.validateRootPathString(originalPathString);
74+
8075
ParsedUrl parsedUrl = new ParsedUrl();
81-
parsedUrl.path = path;
76+
parsedUrl.path = new Path(originalPathString);
8277
parsedUrl.repoInfo = repoInfo;
83-
return parsedUrl;
8478

85-
} catch (URISyntaxException e) {
86-
throw new DatabaseException("Invalid Firebase Database url specified", e);
87-
} catch (UnsupportedEncodingException e) {
88-
throw new DatabaseException("Failed to URLEncode the path", e);
79+
return parsedUrl;
80+
} catch (Exception e) {
81+
throw new DatabaseException("Invalid Firebase Database url specified: " + url, e);
8982
}
9083
}
9184

92-
public static String[] splitIntoFrames(String src, int maxFrameSize) {
93-
if (src.length() <= maxFrameSize) {
94-
return new String[] {src};
95-
} else {
96-
ArrayList<String> segs = new ArrayList<String>();
97-
for (int i = 0; i < src.length(); i += maxFrameSize) {
98-
int end = Math.min(i + maxFrameSize, src.length());
99-
String seg = src.substring(i, end);
100-
segs.add(seg);
85+
/**
86+
* Extracts the path string from the original URL without changing the encoding (unlike
87+
* Uri.getPath()).
88+
*/
89+
private static String extractPathString(String originalUrl) {
90+
int schemeOffset = originalUrl.indexOf("//");
91+
if (schemeOffset == -1) {
92+
throw new DatabaseException("Firebase Database URL is missing URL scheme");
93+
}
94+
95+
String urlWithoutScheme = originalUrl.substring(schemeOffset + 2);
96+
int pathOffset = urlWithoutScheme.indexOf("/");
97+
if (pathOffset != -1) {
98+
int queryOffset = urlWithoutScheme.indexOf("?");
99+
if (queryOffset != -1) {
100+
return urlWithoutScheme.substring(pathOffset + 1, queryOffset);
101+
} else {
102+
return urlWithoutScheme.substring(pathOffset + 1);
101103
}
102-
return segs.toArray(new String[segs.size()]);
104+
} else {
105+
return "";
103106
}
104107
}
105108

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2019 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.google.firebase.database.core.utilities;
16+
17+
import static org.junit.Assert.assertEquals;
18+
import static org.junit.Assert.assertFalse;
19+
import static org.junit.Assert.assertTrue;
20+
21+
import com.google.firebase.database.DatabaseException;
22+
import org.junit.Test;
23+
import org.robolectric.RobolectricTestRunner;
24+
import org.robolectric.annotation.Config;
25+
26+
@org.junit.runner.RunWith(RobolectricTestRunner.class)
27+
@Config(manifest = Config.NONE)
28+
public class ParseUrlTest {
29+
30+
@Test
31+
public void testUrlParsing() throws DatabaseException {
32+
ParsedUrl parsed = Utilities.parseUrl("http://gsoltis.fblocal.com:9000");
33+
assertEquals("/", parsed.path.toString());
34+
assertEquals("gsoltis.fblocal.com:9000", parsed.repoInfo.host);
35+
assertEquals("gsoltis.fblocal.com:9000", parsed.repoInfo.internalHost);
36+
37+
parsed = Utilities.parseUrl("http://gsoltis.firebaseio.com/foo/bar");
38+
assertEquals("/foo/bar", parsed.path.toString());
39+
assertEquals("gsoltis.firebaseio.com", parsed.repoInfo.host);
40+
assertEquals("gsoltis.firebaseio.com", parsed.repoInfo.internalHost);
41+
42+
parsed = Utilities.parseUrl("http://gsoltis.firebaseio.com/foo/empty space");
43+
assertEquals("/foo/empty space", parsed.path.toString());
44+
assertEquals("gsoltis.firebaseio.com", parsed.repoInfo.host);
45+
assertEquals("gsoltis.firebaseio.com", parsed.repoInfo.internalHost);
46+
47+
parsed = Utilities.parseUrl("http://gsoltis.firebaseio.com/foo/\\;:@\uD83D\uDE00");
48+
assertEquals("/foo/\\;:@\uD83D\uDE00", parsed.path.toString());
49+
assertEquals("gsoltis.firebaseio.com", parsed.repoInfo.host);
50+
assertEquals("gsoltis.firebaseio.com", parsed.repoInfo.internalHost);
51+
}
52+
53+
@Test
54+
public void testUrlParsingTurnsPlusIntoSpace() throws DatabaseException {
55+
ParsedUrl parsed = Utilities.parseUrl("http://gsoltis.firebaseio.com/+");
56+
assertEquals("/ ", parsed.path.toString());
57+
}
58+
59+
@Test
60+
public void testUrlParsingSpecialCharacters() throws DatabaseException {
61+
ParsedUrl parsed =
62+
Utilities.parseUrl("http://gsoltis.firebaseio.com/a%b&c@d/+space: /non-ascii:ø");
63+
assertEquals("/a%b&c@d/ space: /non-ascii:ø", parsed.path.toString());
64+
}
65+
66+
@Test
67+
public void testUrlParsingIgnoresTrailingSlash() throws DatabaseException {
68+
ParsedUrl parsed1 = Utilities.parseUrl("http://gsoltis.firebaseio.com/");
69+
ParsedUrl parsed2 = Utilities.parseUrl("http://gsoltis.firebaseio.com");
70+
assertEquals(parsed1, parsed2);
71+
}
72+
73+
@Test
74+
public void testUrlParsingWithNamespace() throws DatabaseException {
75+
ParsedUrl parsed = Utilities.parseUrl("http://localhost/foo/bar?ns=mrschmidt");
76+
assertEquals("mrschmidt", parsed.repoInfo.namespace);
77+
78+
parsed = Utilities.parseUrl("http://10.0.2.2:9000/foo/bar?ns=mrschmidt");
79+
assertEquals(parsed.path.toString(), "/foo/bar");
80+
assertEquals("mrschmidt", parsed.repoInfo.namespace);
81+
}
82+
83+
@Test
84+
public void testUrlParsingSslDetection() throws DatabaseException {
85+
// Hosts with custom ports are considered non-secure
86+
ParsedUrl parsed = Utilities.parseUrl("http://gsoltis.fblocal.com:9000");
87+
assertFalse(parsed.repoInfo.secure);
88+
89+
// Hosts with the default ports are considered secure
90+
parsed = Utilities.parseUrl("http://gsoltis.firebaseio.com");
91+
assertTrue(parsed.repoInfo.secure);
92+
}
93+
}

firebase-firestore/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Unreleased
2+
3+
# 21.0.0
24
- [changed] Transactions are now more flexible. Some sequences of operations
35
that were previously incorrectly disallowed are now allowed. For example,
46
after reading a document that doesn't exist, you can now set it multiple

0 commit comments

Comments
 (0)