diff --git a/.github/ISSUE_TEMPLATE/--general-question.md b/.github/ISSUE_TEMPLATE/--general-question.md
new file mode 100644
index 0000000000..f354c77a4f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/--general-question.md
@@ -0,0 +1,28 @@
+---
+name: "❓ General question"
+about: Describe this issue template's purpose here.
+title: "[Question] "
+labels: 'new, type: question'
+assignees: ''
+
+---
+
+
+
+### [READ] For Firebase Unity SDK question, please report to [Firebase Unity Sample](https://github.com/firebase/quickstart-unity/issues/new/choose)
+
+Once you've read this section and determined that your issue is appropriate for this repository, please delete this section.
+
+### [REQUIRED] Please fill in the following fields:
+
+ * Pre-built SDK from the [website](https://firebase.google.com/download/cpp) or open-source from this repo: _____
+ * Firebase C++ SDK version: _____
+ * Main Firebase Components in concern: _____ (Auth, Database, etc.)
+ * Other Firebase Components in use: _____ (Auth, Database, etc.)
+ * Platform you are using the C++ SDK on: _____ (Mac, Windows, or Linux)
+ * Platform you are targeting: _____ (iOS, Android, and/or desktop)
+
+### [REQUIRED] Please describe the question here:
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
new file mode 100644
index 0000000000..d20d8a8c44
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -0,0 +1,30 @@
+---
+name: "➕ Feature request"
+about: If you have a feature request for the Firebase C++ SDK, file it here.
+title: ''
+labels: 'new, type: feature request'
+assignees: ''
+
+---
+
+
+### [READ] Guidelines
+
+When filing a feature request please make sure the issue title starts with "FR:".
+
+A good feature request ideally
+* is either immediately obvious (i.e. "Add Sign in with Apple support"), or
+* starts with a use case that is not achievable with the existing Firebase API and
+ includes an API proposal that would make the use case possible. The proposed API
+ change does not need to be very specific.
+
+Once you've read this section, please delete it and fill out the rest of the template.
+
+### Feature proposal
+
+* Firebase Component: _____ (Auth, Core, Database, Firestore, Messaging, Storage, etc)
+
+Describe your use case and/or feature request here.
diff --git a/.github/ISSUE_TEMPLATE/firebase-cpp-sdk-issue.md b/.github/ISSUE_TEMPLATE/firebase-cpp-sdk-issue.md
deleted file mode 100644
index 916a4ce47f..0000000000
--- a/.github/ISSUE_TEMPLATE/firebase-cpp-sdk-issue.md
+++ /dev/null
@@ -1,24 +0,0 @@
----
-name: Firebase C++ SDK issue
-about: Please use this template to report issues with the Firebase C++ SDK.
-title: ''
-labels: new
-assignees: ''
-
----
-
-### Please fill in the following fields:
-Pre-built SDK from the [website](https://firebase.google.com/download/cpp) or open-source from this repo:
-Firebase C++ SDK version:
-Firebase plugins in use (Auth, Database, etc.):
-Additional SDKs you are using (Facebook, AdMob, etc.):
-Platform you are using the C++ SDK on (Mac, Windows, or Linux):
-Platform you are targeting (iOS, Android, and/or desktop):
-
-### Please describe the issue here:
-(Please list the full steps to reproduce the issue. Include device logs, Unity logs, and stack traces if available.)
-
-### Please answer the following, if applicable:
-Have you been able to reproduce this issue with just the [Firebase C++ quickstarts](https://github.com/firebase/quickstart-cpp) ?
-
-What's the issue repro rate? (eg 100%, 1/5 etc)
diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md
new file mode 100644
index 0000000000..45eb75e9d6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/issue.md
@@ -0,0 +1,43 @@
+---
+name: "\U0001F41E Bug report"
+about: Please use this template to report bugs with the Firebase C++ SDK.
+title: ''
+labels: new
+assignees: ''
+
+---
+
+
+
+### [REQUIRED] Please fill in the following fields:
+
+ * Pre-built SDK from the [website](https://firebase.google.com/download/cpp) or open-source from this repo: _____
+ * Firebase C++ SDK version: _____
+ * Problematic Firebase Component: _____ (Auth, Database, etc.)
+ * Other Firebase Components in use: _____ (Auth, Database, etc.)
+ * Platform you are using the C++ SDK on: _____ (Mac, Windows, or Linux)
+ * Platform you are targeting: _____ (iOS, Android, and/or desktop)
+
+### [REQUIRED] Please describe the issue here:
+
+(Please list the full steps to reproduce the issue. Include device logs, Unity logs, and stack traces if available.)
+
+#### Steps to reproduce:
+
+Have you been able to reproduce this issue with just the [Firebase C++ quickstarts](https://github.com/firebase/quickstart-cpp) ?
+What's the issue repro rate? (eg 100%, 1/5 etc)
+
+What happened? How can we make the problem occur?
+This could be a description, log/console output, etc.
+
+If you have a downloadable sample project that reproduces the bug you're reporting, you will
+likely receive a faster response on your issue.
+
+#### Relevant Code:
+
+```
+// TODO(you): code here to reproduce the problem
+```
diff --git a/Android/firebase_dependencies.gradle b/Android/firebase_dependencies.gradle
index 4ae98c201c..8c2ff4d638 100644
--- a/Android/firebase_dependencies.gradle
+++ b/Android/firebase_dependencies.gradle
@@ -16,23 +16,27 @@ import org.gradle.util.ConfigureUtil;
// A map of library to the dependencies that need to be added for it.
def firebaseDependenciesMap = [
- 'app' : ['com.google.firebase:firebase-analytics:17.4.4'],
- 'admob' : ['com.google.firebase:firebase-ads:19.2.0',
- 'com.google.android.gms:play-services-measurement-sdk-api:17.4.4'],
- 'analytics' : ['com.google.firebase:firebase-analytics:17.4.4'],
+ 'app' : ['com.google.firebase:firebase-analytics:17.5.0'],
+ 'admob' : ['com.google.firebase:firebase-ads:19.3.0',
+ 'com.google.android.gms:play-services-measurement-sdk-api:17.5.0',
+ 'com.google.android.gms:play-services-base:17.4.0'],
+ 'analytics' : ['com.google.firebase:firebase-analytics:17.5.0',
+ 'com.google.android.gms:play-services-base:17.4.0'],
'auth' : ['com.google.firebase:firebase-auth:19.3.2'],
- 'database' : ['com.google.firebase:firebase-database:19.3.1'],
+ 'database' : ['com.google.firebase:firebase-database:19.4.0'],
'dynamic_links' : ['com.google.firebase:firebase-dynamic-links:19.1.0'],
- 'firestore' : ['com.google.firebase:firebase-firestore:21.5.0'],
- 'functions' : ['com.google.firebase:firebase-functions:19.0.2'],
- 'instance_id' : ['com.google.firebase:firebase-iid:20.2.3'],
+ 'firestore' : ['com.google.firebase:firebase-firestore:21.6.0'],
+ 'functions' : ['com.google.firebase:firebase-functions:19.1.0'],
+ 'instance_id' : ['com.google.firebase:firebase-iid:20.2.4'],
'invites' : ['com.google.firebase:firebase-invites:17.0.0'],
// Messaging has an additional local dependency to include.
- 'messaging' : ['com.google.firebase:firebase-messaging:20.2.3',
- 'firebase_cpp_sdk.messaging:messaging_java'],
- 'performance' : ['com.google.firebase:firebase-perf:19.0.7'],
- 'remote_config' : ['com.google.firebase:firebase-config:19.2.0'],
- 'storage' : ['com.google.firebase:firebase-storage:19.1.1']
+ 'messaging' : ['com.google.firebase:firebase-messaging:20.2.4',
+ 'firebase_cpp_sdk.messaging:messaging_java',
+ 'androidx.core:core:1.0.1'],
+ 'performance' : ['com.google.firebase:firebase-perf:19.0.8'],
+ 'remote_config' : ['com.google.firebase:firebase-config:19.2.0',
+ 'com.google.android.gms:play-services-base:17.4.0'],
+ 'storage' : ['com.google.firebase:firebase-storage:19.2.0']
]
// A map of library to the gradle resources that they depend upon.
@@ -157,4 +161,4 @@ project.afterEvaluate {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/admob/admob_resources/build.gradle b/admob/admob_resources/build.gradle
index 4597cc77d0..ecab34f893 100644
--- a/admob/admob_resources/build.gradle
+++ b/admob/admob_resources/build.gradle
@@ -45,8 +45,8 @@ android {
}
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
- implementation 'com.google.firebase:firebase-ads:19.2.0'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
+ implementation 'com.google.firebase:firebase-ads:19.3.0'
}
afterEvaluate {
@@ -54,4 +54,4 @@ afterEvaluate {
}
apply from: "$rootDir/android_build_files/extract_and_dex.gradle"
-extractAndDexAarFile('admob_resources')
\ No newline at end of file
+extractAndDexAarFile('admob_resources')
diff --git a/admob/src/include/firebase/admob/types.h b/admob/src/include/firebase/admob/types.h
index b9f04cebb4..d1e3d28e75 100644
--- a/admob/src/include/firebase/admob/types.h
+++ b/admob/src/include/firebase/admob/types.h
@@ -72,6 +72,8 @@ enum AdMobError {
/// An attempt has been made to show an ad on an Android Activity that has
/// no window token (such as one that's not done initializing).
kAdMobErrorNoWindowToken,
+ /// Fallback error for any unidentified cases.
+ kAdMobErrorUnknown,
};
#ifdef INTERNAL_EXPERIMENTAL
// LINT.ThenChange(//depot_firebase_cpp/admob/client/cpp/src_java/com/google/firebase/admob/internal/cpp/ConstantsHelper.java)
diff --git a/admob/src_java/com/google/firebase/admob/internal/cpp/ConstantsHelper.java b/admob/src_java/com/google/firebase/admob/internal/cpp/ConstantsHelper.java
index d226ea8ad3..0687ba7f52 100644
--- a/admob/src_java/com/google/firebase/admob/internal/cpp/ConstantsHelper.java
+++ b/admob/src_java/com/google/firebase/admob/internal/cpp/ConstantsHelper.java
@@ -40,6 +40,8 @@ public final class ConstantsHelper {
public static final int CALLBACK_ERROR_NO_FILL = 7;
public static final int CALLBACK_ERROR_NO_WINDOW_TOKEN = 8;
+
+ public static final int CALLBACK_ERROR_UNKNOWN = 9;
// LINT.ThenChange(//depot_firebase_cpp/admob/client/cpp/src/include/firebase/admob/types.h)
/**
@@ -68,6 +70,8 @@ public final class ConstantsHelper {
public static final String CALLBACK_ERROR_MESSAGE_NO_WINDOW_TOKEN =
"Android Activity does not have a window token.";
+
+ public static final String CALLBACK_ERROR_MESSAGE_UNKNOWN = "Unknown error occurred.";
// LINT.ThenChange(//depot_firebase_cpp/admob/client/cpp/src/include/firebase/admob/types.h)
/** Types of notifications to send back to the C++ side for listeners updates. */
diff --git a/admob/src_java/com/google/firebase/admob/internal/cpp/InterstitialAdHelper.java b/admob/src_java/com/google/firebase/admob/internal/cpp/InterstitialAdHelper.java
index eee1149e08..60b7183de7 100644
--- a/admob/src_java/com/google/firebase/admob/internal/cpp/InterstitialAdHelper.java
+++ b/admob/src_java/com/google/firebase/admob/internal/cpp/InterstitialAdHelper.java
@@ -92,14 +92,22 @@ public void run() {
int errorCode;
String errorMessage;
if (mInterstitial == null) {
- errorCode = ConstantsHelper.CALLBACK_ERROR_NONE;
- errorMessage = ConstantsHelper.CALLBACK_ERROR_MESSAGE_NONE;
- mInterstitial = new InterstitialAd(mActivity);
- mInterstitial.setAdUnitId(mAdUnitId);
- mInterstitial.setAdListener(new InterstitialAdListener());
+ try {
+ mInterstitial = new InterstitialAd(mActivity);
+ mInterstitial.setAdUnitId(mAdUnitId);
+ mInterstitial.setAdListener(new InterstitialAdListener());
+ errorCode = ConstantsHelper.CALLBACK_ERROR_NONE;
+ errorMessage = ConstantsHelper.CALLBACK_ERROR_MESSAGE_NONE;
+ } catch (IllegalStateException e) {
+ mInterstitial = null;
+ // This exception can be thrown if the ad unit ID was already set.
+ errorCode = ConstantsHelper.CALLBACK_ERROR_ALREADY_INITIALIZED;
+ errorMessage = ConstantsHelper.CALLBACK_ERROR_MESSAGE_ALREADY_INITIALIZED;
+ }
} else {
errorCode = ConstantsHelper.CALLBACK_ERROR_ALREADY_INITIALIZED;
errorMessage = ConstantsHelper.CALLBACK_ERROR_MESSAGE_ALREADY_INITIALIZED;
+
}
completeInterstitialAdFutureCallback(callbackDataPtr, errorCode, errorMessage);
@@ -152,7 +160,17 @@ public void run() {
mLoadAdCallbackDataPtr = CPP_NULLPTR;
}
} else {
- mInterstitial.loadAd(request);
+ try {
+ mInterstitial.loadAd(request);
+ } catch (IllegalStateException e) {
+ synchronized (mInterstitialLock) {
+ completeInterstitialAdFutureCallback(
+ mLoadAdCallbackDataPtr,
+ ConstantsHelper.CALLBACK_ERROR_UNINITIALIZED,
+ ConstantsHelper.CALLBACK_ERROR_MESSAGE_UNINITIALIZED);
+ mLoadAdCallbackDataPtr = CPP_NULLPTR;
+ }
+ }
}
}
});
@@ -222,6 +240,9 @@ public void onAdFailedToLoad(int errorCode) {
callbackErrorCode = ConstantsHelper.CALLBACK_ERROR_NO_FILL;
callbackErrorMessage = ConstantsHelper.CALLBACK_ERROR_MESSAGE_NO_FILL;
break;
+ default:
+ callbackErrorCode = ConstantsHelper.CALLBACK_ERROR_UNKNOWN;
+ callbackErrorMessage = ConstantsHelper.CALLBACK_ERROR_MESSAGE_UNKNOWN;
}
synchronized (mInterstitialLock) {
@@ -233,11 +254,6 @@ public void onAdFailedToLoad(int errorCode) {
super.onAdFailedToLoad(errorCode);
}
- @Override
- public void onAdLeftApplication() {
- super.onAdLeftApplication();
- }
-
@Override
public void onAdLoaded() {
synchronized (mInterstitialLock) {
diff --git a/analytics/ios_headers/FIREventNames.h b/analytics/ios_headers/FIREventNames.h
index 9458782579..f7984ca777 100644
--- a/analytics/ios_headers/FIREventNames.h
+++ b/analytics/ios_headers/FIREventNames.h
@@ -69,6 +69,21 @@ static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart)
static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) =
@"add_to_wishlist";
+/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply
+/// the @c kFIRParameterValue parameter, you must also supply the @c kFIRParameterCurrency parameter
+/// so that revenue metrics can be computed accurately. Params:
+///
+///
+/// @c kFIRParameterAdPlatform (NSString) (optional)
+/// @c kFIRParameterAdFormat (NSString) (optional)
+/// @c kFIRParameterAdSource (NSString) (optional)
+/// @c kFIRParameterAdUnitName (NSString) (optional)
+/// @c kFIRParameterCurrency (NSString) (optional)
+/// @c kFIRParameterValue (double as NSNumber) (optional)
+///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) =
+ @"ad_impression";
+
/// App Open event. By logging this event when an App becomes active, developers can understand how
/// often users leave and return during the course of a Session. Although Sessions are automatically
/// reported, this event can provide further clarification around the continuous engagement of
diff --git a/analytics/ios_headers/FIRParameterNames.h b/analytics/ios_headers/FIRParameterNames.h
index 515232e9b5..6047f5684a 100644
--- a/analytics/ios_headers/FIRParameterNames.h
+++ b/analytics/ios_headers/FIRParameterNames.h
@@ -39,6 +39,17 @@
static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) =
@"achievement_id";
+/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream).
+/// (NSString).
+///
+/// NSDictionary *params = @{
+/// kFIRParameterAdFormat : @"Banner",
+/// // ...
+/// };
+///
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) =
+ @"ad_format";
+
/// Ad Network Click ID (NSString). Used for network-specific click IDs which vary in format.
///
/// NSDictionary *params = @{
@@ -49,6 +60,36 @@ static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParamet
static NSString *const kFIRParameterAdNetworkClickID
NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid";
+/// The ad platform (e.g. MoPub, IronSource) (NSString).
+///
+/// NSDictionary *params = @{
+/// kFIRParameterAdPlatform : @"MoPub",
+/// // ...
+/// };
+///
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) =
+ @"ad_platform";
+
+/// The ad source (e.g. AdColony) (NSString).
+///
+/// NSDictionary *params = @{
+/// kFIRParameterAdSource : @"AdColony",
+/// // ...
+/// };
+///
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) =
+ @"ad_source";
+
+/// The ad unit name (e.g. Banner_03) (NSString).
+///
+/// NSDictionary *params = @{
+/// kFIRParameterAdUnitName : @"Banner_03",
+/// // ...
+/// };
+///
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) =
+ @"ad_unit_name";
+
/// A product affiliation to designate a supplying company or brick and mortar store location
/// (NSString).
/// NSDictionary *params = @{
diff --git a/app/app_resources/build.gradle b/app/app_resources/build.gradle
index f4110eedf5..d6d13928c2 100644
--- a/app/app_resources/build.gradle
+++ b/app/app_resources/build.gradle
@@ -46,7 +46,7 @@ android {
}
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
}
afterEvaluate {
@@ -54,4 +54,4 @@ afterEvaluate {
}
apply from: "$rootDir/android_build_files/extract_and_dex.gradle"
-extractAndDexAarFile('app_resources')
\ No newline at end of file
+extractAndDexAarFile('app_resources')
diff --git a/app/google_api_resources/build.gradle b/app/google_api_resources/build.gradle
index 0d3076b981..f54e91e465 100644
--- a/app/google_api_resources/build.gradle
+++ b/app/google_api_resources/build.gradle
@@ -49,7 +49,7 @@ android {
}
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
implementation 'com.google.android.gms:play-services-base:17.0.0'
implementation project(':app:app_resources')
}
@@ -59,4 +59,4 @@ afterEvaluate {
}
apply from: "$rootDir/android_build_files/extract_and_dex.gradle"
-extractAndDexAarFile('google_api_resources')
\ No newline at end of file
+extractAndDexAarFile('google_api_resources')
diff --git a/app/invites_resources/build.gradle b/app/invites_resources/build.gradle
index c5db176719..8215747a6e 100644
--- a/app/invites_resources/build.gradle
+++ b/app/invites_resources/build.gradle
@@ -45,7 +45,7 @@ android {
}
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
implementation 'com.google.firebase:firebase-dynamic-links:19.1.0'
implementation project(':app:app_resources')
}
@@ -55,4 +55,4 @@ afterEvaluate {
}
apply from: "$rootDir/android_build_files/extract_and_dex.gradle"
-extractAndDexAarFile('invites_resources')
\ No newline at end of file
+extractAndDexAarFile('invites_resources')
diff --git a/app/src/include/firebase/variant.h b/app/src/include/firebase/variant.h
index 77a0796e6b..86aa6bed88 100644
--- a/app/src/include/firebase/variant.h
+++ b/app/src/include/firebase/variant.h
@@ -131,7 +131,7 @@ class Variant {
template
Variant(T value) // NOLINT
: type_(kInternalTypeNull) {
- set_value_t(value);
+ set_value_t(value);
}
/// @brief Construct a Variant containing the given string value (makes a
@@ -1104,14 +1104,11 @@ class Variant {
value_.blob_value.size = size;
}
- // Templated helper function to ensure the value 0 is constructed as int
- // instead of nullptr char*
- //
// If you hit a compiler error here it means you are trying to construct a
// variant with unsupported type. Ether cast to correct type or add support
// below.
template
- void set_value_t(T value);
+ void set_value_t(T value) = delete;
// Get whether this Variant contains a small string.
bool is_small_string() const { return type_ == kInternalTypeSmallString; }
diff --git a/auth/auth_resources/build.gradle b/auth/auth_resources/build.gradle
index 25e0263958..aa9640bb74 100644
--- a/auth/auth_resources/build.gradle
+++ b/auth/auth_resources/build.gradle
@@ -45,7 +45,7 @@ android {
}
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
implementation 'com.google.firebase:firebase-auth:19.3.2'
implementation project(':app:app_resources')
}
diff --git a/auth/src/include/firebase/auth.h b/auth/src/include/firebase/auth.h
index c852486248..043f531720 100644
--- a/auth/src/include/firebase/auth.h
+++ b/auth/src/include/firebase/auth.h
@@ -47,7 +47,7 @@ class PhoneAuthProvider;
struct AuthCompletionHandle;
class FederatedAuthProvider;
class FederatedOAuthProvider;
-class SignInResult;
+struct SignInResult;
/// @brief Firebase authentication object.
///
diff --git a/cpp_sdk_version.json b/cpp_sdk_version.json
index 5f4404eb40..a32751a9ab 100644
--- a/cpp_sdk_version.json
+++ b/cpp_sdk_version.json
@@ -1,5 +1,5 @@
{
- "released": "6.15.1",
- "stable": "6.15.1",
- "head": "6.15.1"
+ "released": "6.16.0",
+ "stable": "6.16.0",
+ "head": "6.16.0"
}
diff --git a/database/database_resources/build.gradle b/database/database_resources/build.gradle
index b5040464df..0231afd804 100644
--- a/database/database_resources/build.gradle
+++ b/database/database_resources/build.gradle
@@ -45,8 +45,8 @@ android {
}
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
- implementation 'com.google.firebase:firebase-database:19.3.1'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
+ implementation 'com.google.firebase:firebase-database:19.4.0'
//implementation project(':app:app_resources')
}
diff --git a/firestore/CMakeLists.txt b/firestore/CMakeLists.txt
index cddeb2ce3b..df77ae105d 100644
--- a/firestore/CMakeLists.txt
+++ b/firestore/CMakeLists.txt
@@ -71,16 +71,14 @@ set(android_SRCS
src/android/document_snapshot_android.h
src/android/event_listener_android.cc
src/android/event_listener_android.h
+ src/android/exception_android.cc
+ src/android/exception_android.h
src/android/field_path_android.cc
src/android/field_path_android.h
src/android/field_path_portable.cc
src/android/field_path_portable.h
src/android/field_value_android.cc
src/android/field_value_android.h
- src/android/firebase_firestore_exception_android.cc
- src/android/firebase_firestore_exception_android.h
- src/android/firebase_firestore_settings_android.cc
- src/android/firebase_firestore_settings_android.h
src/android/firestore_android.cc
src/android/firestore_android.h
src/android/geo_point_android.cc
@@ -101,6 +99,8 @@ set(android_SRCS
src/android/server_timestamp_behavior_android.h
src/android/set_options_android.cc
src/android/set_options_android.h
+ src/android/settings_android.cc
+ src/android/settings_android.h
src/android/snapshot_metadata_android.cc
src/android/snapshot_metadata_android.h
src/android/source_android.cc
diff --git a/firestore/firestore_resources/build.gradle b/firestore/firestore_resources/build.gradle
index 357394b0cc..04ed413046 100644
--- a/firestore/firestore_resources/build.gradle
+++ b/firestore/firestore_resources/build.gradle
@@ -43,16 +43,11 @@ android {
}
}
}
-
- lintOptions {
- abortOnError false
- }
}
-
dependencies {
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
- implementation 'com.google.firebase:firebase-firestore:21.5.0'
+ implementation 'com.google.firebase:firebase-analytics:17.5.0'
+ implementation 'com.google.firebase:firebase-firestore:21.6.0'
}
afterEvaluate {
diff --git a/firestore/run_local_tests.sh b/firestore/run_local_tests.sh
index 07a1ff0898..b0ef454e40 100755
--- a/firestore/run_local_tests.sh
+++ b/firestore/run_local_tests.sh
@@ -3,9 +3,99 @@
# TAP or Guitar at the moment (see b/135205911). Execute this script before
# submitting.
+set -euo pipefail
+
+# Executes blaze to run a Kokoro test.
+#
+# The first argument is the name of an associative array variable. A key/value
+# pair will be inserted into this associative array with information about the
+# launched blaze process. The key will be the PID of the blaze process and the
+# value will be the full blaze command that was executed.
+#
+# The second argument is the "name" of the test, and is used in the subdirectory
+# name of the directory specified to blaze's --output_base argument.
+#
+# The remaining arguments, if any, will be specified to the blaze command after
+# the "test" argument.
+function run_blaze {
+ if [[ $# -lt 2 ]] ; then
+ echo "INTERNAL ERROR: run_blaze invalid arguments: $*" >&2
+ exit 1
+ fi
+
+ local -n readonly blaze_process_map="$1"
+ local readonly blaze_build_name="$2"
+ shift 2
+
+ local readonly blaze_args=(
+ "blaze"
+ "--blazerc=/dev/null"
+ "--output_base=/tmp/run_local_tests_blaze_output_bases/${blaze_build_name}"
+ "test"
+ "$@"
+ "//firebase/firestore/client/cpp:kokoro_build_test"
+ )
+
+ echo "${blaze_args[*]}"
+ "${blaze_args[@]}" &
+ blaze_process_map["$!"]="${blaze_args[*]}"
+}
+
+# Waits for blaze commands started by `run_blaze` to complete.
+#
+# If all blaze commands complete successfully then a "success" message is
+# printed; otherwise, if one or more of the blaze commands fail, then an error
+# message is printed.
+#
+# The first (and only) argument is the name of an associative array variable.
+# This variable should be the same that was was specified to `run_blaze` and
+# specifies the blaze commands for which to wait.
+#
+# The return value is 0 if all blaze processes completed successfully or 1 if
+# one or more of the blaze processes failed.
+function wait_for_blazes_to_complete {
+ if [[ $# -ne 1 ]] ; then
+ echo "INTERNAL ERROR: wait_for_blazes_to_complete invalid arguments: $*" >&2
+ exit 1
+ fi
+
+ local -n blaze_process_map="$1"
+
+ local blaze_pid
+ local -a blaze_failed_pids=()
+
+ for blaze_pid in "${!blaze_process_map[@]}" ; do
+ if ! wait "${blaze_pid}" ; then
+ blaze_failed_pids+=("${blaze_pid}")
+ fi
+ done
+
+ local readonly num_failed_blazes="${#blaze_failed_pids[@]}"
+ if [[ ${num_failed_blazes} -eq 0 ]] ; then
+ echo "All blaze commands completed successfully."
+ else
+ echo "ERROR: The following ${num_failed_blazes} blaze invocation(s) failed:"
+ for blaze_pid in "${blaze_failed_pids[@]}" ; do
+ echo "${blaze_process_map[${blaze_pid}]}"
+ done
+ echo "Go to http://sponge2 to see the results."
+ return 1
+ fi
+}
+
+# The main program begins here.
+if [[ $# -gt 0 ]] ; then
+ echo "ERROR: $0 does not accept any arguments, but got: $*" >&2
+ exit 2
+fi
+
+declare -A BLAZE_PROCESS_MAP
+
# LINT.IfChange
-blaze test --config=android_arm //firebase/firestore/client/cpp:kokoro_build_test && \
-blaze test --config=darwin_x86_64 //firebase/firestore/client/cpp:kokoro_build_test && \
-blaze test //firebase/firestore/client/cpp:kokoro_build_test && \
-blaze test --config=msvc //firebase/firestore/client/cpp:kokoro_build_test
+run_blaze "BLAZE_PROCESS_MAP" "android_arm" "--config=android_arm"
+run_blaze "BLAZE_PROCESS_MAP" "darwin_x86_64" "--config=darwin_x86_64"
+run_blaze "BLAZE_PROCESS_MAP" "linux" "--define=force_regular_grpc=1"
+run_blaze "BLAZE_PROCESS_MAP" "msvc" "--config=msvc"
# LINT.ThenChange(//depot_firebase_cpp/firestore/client/cpp/METADATA)
+
+wait_for_blazes_to_complete "BLAZE_PROCESS_MAP"
diff --git a/firestore/src/android/blob_android.cc b/firestore/src/android/blob_android.cc
index 8e7091b6d3..ac68a1d173 100644
--- a/firestore/src/android/blob_android.cc
+++ b/firestore/src/android/blob_android.cc
@@ -1,62 +1,48 @@
#include "firestore/src/android/blob_android.h"
-#include "app/src/util_android.h"
-#include "firestore/src/android/util_android.h"
+#include "firestore/src/jni/array.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
-
-// clang-format off
-#define BLOB_METHODS(X) \
- X(Constructor, "", "(Lcom/google/protobuf/ByteString;)V", \
- util::kMethodTypeInstance), \
- X(FromBytes, "fromBytes", "([B)Lcom/google/firebase/firestore/Blob;", \
- util::kMethodTypeStatic), \
- X(ToBytes, "toBytes", "()[B")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(blob, BLOB_METHODS)
-METHOD_LOOKUP_DEFINITION(blob,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/Blob",
- BLOB_METHODS)
-
-/* static */
-jobject BlobInternal::BlobToJavaBlob(JNIEnv* env, const uint8_t* value,
- size_t size) {
- jobject byte_array = util::ByteBufferToJavaByteArray(env, value, size);
- jobject result = env->CallStaticObjectMethod(
- blob::GetClass(), blob::GetMethodId(blob::kFromBytes), byte_array);
- env->DeleteLocalRef(byte_array);
- CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-jbyteArray BlobInternal::JavaBlobToJbyteArray(JNIEnv* env, jobject obj) {
- jbyteArray result = static_cast(
- env->CallObjectMethod(obj, blob::GetMethodId(blob::kToBytes)));
- CheckAndClearJniExceptions(env);
- return result;
+namespace {
+
+using jni::Array;
+using jni::Class;
+using jni::Env;
+using jni::Local;
+using jni::Method;
+using jni::Object;
+using jni::StaticMethod;
+
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Blob";
+jclass g_class = nullptr;
+
+Method kConstructor("", "(Lcom/google/protobuf/ByteString;)V");
+StaticMethod kFromBytes(
+ "fromBytes", "([B)Lcom/google/firebase/firestore/Blob;");
+Method> kToBytes("toBytes", "()[B");
+
+} // namespace
+
+void BlobInternal::Initialize(jni::Loader& loader) {
+ g_class = loader.LoadClass(kClass);
+ loader.LoadAll(kConstructor, kFromBytes, kToBytes);
}
-/* static */
-jclass BlobInternal::GetClass() { return blob::GetClass(); }
+Class BlobInternal::GetClass() { return Class(g_class); }
-/* static */
-bool BlobInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = blob::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
+Local BlobInternal::Create(Env& env, const uint8_t* value,
+ size_t size) {
+ Local> byte_array = env.NewArray(size);
+ env.SetArrayRegion(byte_array, 0, size, value);
+ return env.Call(kFromBytes, byte_array);
}
-/* static */
-void BlobInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- blob::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
+Local> BlobInternal::ToBytes(Env& env) const {
+ return env.Call(*this, kToBytes);
}
} // namespace firestore
diff --git a/firestore/src/android/blob_android.h b/firestore/src/android/blob_android.h
index 96e0c43a14..187072a4c4 100644
--- a/firestore/src/android/blob_android.h
+++ b/firestore/src/android/blob_android.h
@@ -1,26 +1,24 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_BLOB_ANDROID_H_
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_BLOB_ANDROID_H_
-#include
-
-#include "app/src/include/firebase/app.h"
+#include "firestore/src/jni/jni_fwd.h"
+#include "firestore/src/jni/object.h"
namespace firebase {
namespace firestore {
-class BlobInternal {
+class BlobInternal : public jni::Object {
public:
- static jobject BlobToJavaBlob(JNIEnv* env, const uint8_t* value, size_t size);
+ using Object::Object;
- static jbyteArray JavaBlobToJbyteArray(JNIEnv* env, jobject obj);
+ static void Initialize(jni::Loader& loader);
- static jclass GetClass();
+ static jni::Class GetClass();
- private:
- friend class FirestoreInternal;
+ static jni::Local Create(jni::Env& env, const uint8_t* value,
+ size_t size);
- static bool Initialize(App* app);
- static void Terminate(App* app);
+ jni::Local> ToBytes(jni::Env& env) const;
};
} // namespace firestore
diff --git a/firestore/src/android/collection_reference_android.cc b/firestore/src/android/collection_reference_android.cc
index 4170892604..20637cb4be 100644
--- a/firestore/src/android/collection_reference_android.cc
+++ b/firestore/src/android/collection_reference_android.cc
@@ -1,6 +1,5 @@
#include "firestore/src/android/collection_reference_android.h"
-
#include
#include
@@ -9,133 +8,89 @@
#include "firestore/src/android/field_value_android.h"
#include "firestore/src/android/promise_android.h"
#include "firestore/src/android/util_android.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
-
-// clang-format off
-#define COLLECTION_REFERENCE_METHODS(X) \
- X(GetId, "getId", "()Ljava/lang/String;"), \
- X(GetPath, "getPath", "()Ljava/lang/String;"), \
- X(GetParent, "getParent", \
- "()Lcom/google/firebase/firestore/DocumentReference;"), \
- X(DocumentAutoId, "document", \
- "()Lcom/google/firebase/firestore/DocumentReference;"), \
- X(Document, "document", "(Ljava/lang/String;)" \
- "Lcom/google/firebase/firestore/DocumentReference;"), \
- X(Add, "add", \
- "(Ljava/lang/Object;)Lcom/google/android/gms/tasks/Task;")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(collection_reference, COLLECTION_REFERENCE_METHODS)
-METHOD_LOOKUP_DEFINITION(collection_reference,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/CollectionReference",
- COLLECTION_REFERENCE_METHODS)
+namespace {
+
+using jni::Class;
+using jni::Env;
+using jni::Local;
+using jni::Method;
+using jni::Object;
+using jni::String;
+
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/CollectionReference";
+
+Method kGetId("getId", "()Ljava/lang/String;");
+Method kGetPath("getPath", "()Ljava/lang/String;");
+Method kGetParent(
+ "getParent", "()Lcom/google/firebase/firestore/DocumentReference;");
+Method kDocumentAutoId(
+ "document", "()Lcom/google/firebase/firestore/DocumentReference;");
+Method kDocument("document",
+ "(Ljava/lang/String;)"
+ "Lcom/google/firebase/firestore/DocumentReference;");
+Method kAdd("add",
+ "(Ljava/lang/Object;)Lcom/google/android/gms/tasks/Task;");
+
+} // namespace
+
+void CollectionReferenceInternal::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kClass, kGetId, kGetPath, kGetParent, kDocumentAutoId,
+ kDocument, kAdd);
+}
const std::string& CollectionReferenceInternal::id() const {
- if (!cached_id_.empty()) {
- return cached_id_;
+ if (cached_id_.empty()) {
+ Env env = GetEnv();
+ cached_id_ = env.Call(obj_, kGetId).ToString(env);
}
-
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring id = static_cast(env->CallObjectMethod(
- obj_, collection_reference::GetMethodId(collection_reference::kGetId)));
- cached_id_ = util::JniStringToString(env, id);
- CheckAndClearJniExceptions(env);
-
return cached_id_;
}
const std::string& CollectionReferenceInternal::path() const {
- if (!cached_path_.empty()) {
- return cached_path_;
+ if (cached_path_.empty()) {
+ Env env = GetEnv();
+ cached_path_ = env.Call(obj_, kGetPath).ToString(env);
}
-
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring path = static_cast(env->CallObjectMethod(
- obj_, collection_reference::GetMethodId(collection_reference::kGetPath)));
- cached_path_ = util::JniStringToString(env, path);
- CheckAndClearJniExceptions(env);
-
return cached_path_;
}
DocumentReference CollectionReferenceInternal::Parent() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject parent = env->CallObjectMethod(
- obj_,
- collection_reference::GetMethodId(collection_reference::kGetParent));
- CheckAndClearJniExceptions(env);
- if (parent == nullptr) {
- return DocumentReference();
- } else {
- DocumentReferenceInternal* internal =
- new DocumentReferenceInternal{firestore_, parent};
- env->DeleteLocalRef(parent);
- return DocumentReference(internal);
- }
+ Env env = GetEnv();
+ Local parent = env.Call(obj_, kGetParent);
+ return firestore_->NewDocumentReference(env, parent);
}
DocumentReference CollectionReferenceInternal::Document() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject document = env->CallObjectMethod(
- obj_,
- collection_reference::GetMethodId(collection_reference::kDocumentAutoId));
- DocumentReferenceInternal* internal =
- new DocumentReferenceInternal{firestore_, document};
- env->DeleteLocalRef(document);
- CheckAndClearJniExceptions(env);
- return DocumentReference(internal);
+ Env env = GetEnv();
+ Local document = env.Call(obj_, kDocumentAutoId);
+ return firestore_->NewDocumentReference(env, document);
}
DocumentReference CollectionReferenceInternal::Document(
const std::string& document_path) const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring path_string = env->NewStringUTF(document_path.c_str());
- jobject document = env->CallObjectMethod(
- obj_, collection_reference::GetMethodId(collection_reference::kDocument),
- path_string);
- env->DeleteLocalRef(path_string);
- CheckAndClearJniExceptions(env);
- DocumentReferenceInternal* internal =
- new DocumentReferenceInternal{firestore_, document};
- env->DeleteLocalRef(document);
- CheckAndClearJniExceptions(env);
- return DocumentReference(internal);
+ Env env = GetEnv();
+ Local java_path = env.NewStringUtf(document_path);
+ Local document = env.Call(obj_, kDocument, java_path);
+ return firestore_->NewDocumentReference(env, document);
}
Future CollectionReferenceInternal::Add(
const MapFieldValue& data) {
FieldValueInternal map_value(data);
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject task = env->CallObjectMethod(
- obj_, collection_reference::GetMethodId(collection_reference::kAdd),
- map_value.java_object());
- CheckAndClearJniExceptions(env);
+
+ Env env = GetEnv();
+ Local task = env.Call(obj_, kAdd, map_value.java_object());
auto promise = promises_.MakePromise();
- promise.RegisterForTask(CollectionReferenceFn::kAdd, task);
- env->DeleteLocalRef(task);
- CheckAndClearJniExceptions(env);
+ promise.RegisterForTask(AsyncFn::kAdd, task.get());
return promise.GetFuture();
}
-/* static */
-bool CollectionReferenceInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = collection_reference::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void CollectionReferenceInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- collection_reference::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
-}
-
} // namespace firestore
} // namespace firebase
diff --git a/firestore/src/android/collection_reference_android.h b/firestore/src/android/collection_reference_android.h
index 3b1073be2b..44429793b9 100644
--- a/firestore/src/android/collection_reference_android.h
+++ b/firestore/src/android/collection_reference_android.h
@@ -5,24 +5,27 @@
#include "firestore/src/android/firestore_android.h"
#include "firestore/src/android/query_android.h"
+#include "firestore/src/jni/jni_fwd.h"
namespace firebase {
namespace firestore {
-// To make things simple, CollectionReferenceInternal uses the Future management
-// from its base class, QueryInternal. Each API of CollectionReference that
-// returns a Future needs to define an enum value to QueryFn. For example, a
-// Future-returning method Foo() relies on the enum value QueryFn::kFoo. The
-// enum values are used to identify and manage Future in the Firestore Future
-// manager.
-using CollectionReferenceFn = QueryFn;
-
// This is the Android implementation of CollectionReference.
class CollectionReferenceInternal : public QueryInternal {
public:
using ApiType = CollectionReference;
using QueryInternal::QueryInternal;
+ // To make things simple, CollectionReferenceInternal uses the Future
+ // management from its base class, QueryInternal. Each API of
+ // CollectionReference that returns a Future needs to define an enum value in
+ // QueryFn. For example, a Future-returning method Foo() relies on the enum
+ // value AsyncFn::kFoo. The enum values are used to identify and manage Future
+ // in the Firestore Future manager.
+ using AsyncFn = QueryInternal::AsyncFn;
+
+ static void Initialize(jni::Loader& loader);
+
const std::string& id() const;
const std::string& path() const;
DocumentReference Parent() const;
@@ -33,9 +36,6 @@ class CollectionReferenceInternal : public QueryInternal {
private:
friend class FirestoreInternal;
- static bool Initialize(App* app);
- static void Terminate(App* app);
-
// Below are cached call results.
mutable std::string cached_id_;
mutable std::string cached_path_;
diff --git a/firestore/src/android/direction_android.cc b/firestore/src/android/direction_android.cc
index bb45dfc810..4aaef50e43 100644
--- a/firestore/src/android/direction_android.cc
+++ b/firestore/src/android/direction_android.cc
@@ -1,75 +1,37 @@
#include "firestore/src/android/direction_android.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
+namespace {
-// clang-format off
-#define DIRECTION_METHODS(X) \
- X(Name, "name", "()Ljava/lang/String;")
-#define DIRECTION_FIELDS(X) \
- X(Ascending, "ASCENDING", \
- "Lcom/google/firebase/firestore/Query$Direction;", \
- util::kFieldTypeStatic), \
- X(Descending, "DESCENDING", \
- "Lcom/google/firebase/firestore/Query$Direction;", \
- util::kFieldTypeStatic)
-// clang-format on
+using jni::Env;
+using jni::Local;
+using jni::Object;
+using jni::StaticField;
-METHOD_LOOKUP_DECLARATION(direction, DIRECTION_METHODS, DIRECTION_FIELDS)
-METHOD_LOOKUP_DEFINITION(direction,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/Query$Direction",
- DIRECTION_METHODS, DIRECTION_FIELDS)
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/Query$Direction";
+StaticField kAscending(
+ "ASCENDING", "Lcom/google/firebase/firestore/Query$Direction;");
+StaticField kDescending(
+ "DESCENDING", "Lcom/google/firebase/firestore/Query$Direction;");
-jobject DirectionInternal::ascending_ = nullptr;
-jobject DirectionInternal::descending_ = nullptr;
+} // namespace
-/* static */
-jobject DirectionInternal::ToJavaObject(JNIEnv* env,
- Query::Direction direction) {
+void DirectionInternal::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kClass, kAscending, kDescending);
+}
+
+Local DirectionInternal::Create(Env& env, Query::Direction direction) {
if (direction == Query::Direction::kAscending) {
- return ascending_;
+ return env.Get(kAscending);
} else {
- return descending_;
+ return env.Get(kDescending);
}
}
-/* static */
-bool DirectionInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = direction::CacheMethodIds(env, activity) &&
- direction::CacheFieldIds(env, activity);
- util::CheckAndClearJniExceptions(env);
-
- // Cache Java enum values.
- jobject value = env->GetStaticObjectField(
- direction::GetClass(), direction::GetFieldId(direction::kAscending));
- ascending_ = env->NewGlobalRef(value);
- env->DeleteLocalRef(value);
-
- value = env->GetStaticObjectField(
- direction::GetClass(), direction::GetFieldId(direction::kDescending));
- descending_ = env->NewGlobalRef(value);
- env->DeleteLocalRef(value);
- util::CheckAndClearJniExceptions(env);
-
- return result;
-}
-
-/* static */
-void DirectionInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- direction::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
-
- // Uncache Java enum values.
- env->DeleteGlobalRef(ascending_);
- ascending_ = nullptr;
- env->DeleteGlobalRef(descending_);
- descending_ = nullptr;
-}
-
} // namespace firestore
} // namespace firebase
diff --git a/firestore/src/android/direction_android.h b/firestore/src/android/direction_android.h
index 505c09cdae..88f567ef99 100644
--- a/firestore/src/android/direction_android.h
+++ b/firestore/src/android/direction_android.h
@@ -1,25 +1,18 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DIRECTION_ANDROID_H_
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DIRECTION_ANDROID_H_
-#include "app/src/include/firebase/app.h"
-#include "app/src/util_android.h"
#include "firestore/src/android/query_android.h"
+#include "firestore/src/jni/jni_fwd.h"
namespace firebase {
namespace firestore {
class DirectionInternal {
public:
- static jobject ToJavaObject(JNIEnv* env, Query::Direction direction);
+ static void Initialize(jni::Loader& loader);
- private:
- friend class FirestoreInternal;
-
- static bool Initialize(App* app);
- static void Terminate(App* app);
-
- static jobject ascending_;
- static jobject descending_;
+ static jni::Local Create(jni::Env& env,
+ Query::Direction direction);
};
} // namespace firestore
diff --git a/firestore/src/android/document_change_android.cc b/firestore/src/android/document_change_android.cc
index 323d4df0c6..5f31bcecee 100644
--- a/firestore/src/android/document_change_android.cc
+++ b/firestore/src/android/document_change_android.cc
@@ -1,92 +1,56 @@
#include "firestore/src/android/document_change_android.h"
-#include
-
-#include "app/src/util_android.h"
#include "firestore/src/android/document_change_type_android.h"
#include "firestore/src/android/document_snapshot_android.h"
-#include "firestore/src/android/util_android.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
+namespace {
-using Type = DocumentChange::Type;
+using jni::Env;
+using jni::Local;
+using jni::Method;
+using jni::Object;
-// clang-format off
-#define DOCUMENT_CHANGE_METHODS(X) \
- X(Type, "getType", "()Lcom/google/firebase/firestore/DocumentChange$Type;"), \
- X(Document, "getDocument", \
- "()Lcom/google/firebase/firestore/QueryDocumentSnapshot;"), \
- X(OldIndex, "getOldIndex", "()I"), \
- X(NewIndex, "getNewIndex", "()I")
-// clang-format on
+using Type = DocumentChange::Type;
-METHOD_LOOKUP_DECLARATION(document_change, DOCUMENT_CHANGE_METHODS)
-METHOD_LOOKUP_DEFINITION(document_change,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/DocumentChange",
- DOCUMENT_CHANGE_METHODS)
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/DocumentChange";
+Method kType(
+ "getType", "()Lcom/google/firebase/firestore/DocumentChange$Type;");
+Method kDocument(
+ "getDocument", "()Lcom/google/firebase/firestore/QueryDocumentSnapshot;");
+Method kOldIndex("getOldIndex", "()I");
+Method kNewIndex("getNewIndex", "()I");
-Type DocumentChangeInternal::type() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
+} // namespace
- jobject type = env->CallObjectMethod(
- obj_, document_change::GetMethodId(document_change::kType));
- Type result =
- DocumentChangeTypeInternal::JavaDocumentChangeTypeToDocumentChangeType(
- env, type);
- env->DeleteLocalRef(type);
+void DocumentChangeInternal::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kClass, kDocument, kOldIndex, kNewIndex);
+}
- CheckAndClearJniExceptions(env);
- return result;
+Type DocumentChangeInternal::type() const {
+ Env env = GetEnv();
+ Local type = env.Call(obj_, kType);
+ return type.GetType(env);
}
DocumentSnapshot DocumentChangeInternal::document() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
-
- jobject snapshot = env->CallObjectMethod(
- obj_, document_change::GetMethodId(document_change::kDocument));
- CheckAndClearJniExceptions(env);
-
- DocumentSnapshot result{new DocumentSnapshotInternal{firestore_, snapshot}};
- env->DeleteLocalRef(snapshot);
- return result;
+ Env env = GetEnv();
+ Local snapshot = env.Call(obj_, kDocument);
+ return firestore_->NewDocumentSnapshot(env, snapshot);
}
std::size_t DocumentChangeInternal::old_index() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
-
- jint index = env->CallIntMethod(
- obj_, document_change::GetMethodId(document_change::kOldIndex));
- CheckAndClearJniExceptions(env);
-
- return static_cast(index);
+ Env env = GetEnv();
+ return env.Call(obj_, kOldIndex);
}
std::size_t DocumentChangeInternal::new_index() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
-
- jint index = env->CallIntMethod(
- obj_, document_change::GetMethodId(document_change::kNewIndex));
- CheckAndClearJniExceptions(env);
-
- return static_cast(index);
-}
-
-/* static */
-bool DocumentChangeInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = document_change::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void DocumentChangeInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- document_change::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
+ Env env = GetEnv();
+ return env.Call(obj_, kNewIndex);
}
} // namespace firestore
diff --git a/firestore/src/android/document_change_android.h b/firestore/src/android/document_change_android.h
index 787356d384..938a415d8c 100644
--- a/firestore/src/android/document_change_android.h
+++ b/firestore/src/android/document_change_android.h
@@ -2,10 +2,10 @@
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DOCUMENT_CHANGE_ANDROID_H_
#include
-#include
#include "firestore/src/android/wrapper.h"
#include "firestore/src/include/firebase/firestore/document_change.h"
+#include "firestore/src/jni/jni_fwd.h"
namespace firebase {
namespace firestore {
@@ -15,16 +15,12 @@ class DocumentChangeInternal : public Wrapper {
using ApiType = DocumentChange;
using Wrapper::Wrapper;
+ static void Initialize(jni::Loader& loader);
+
DocumentChange::Type type() const;
DocumentSnapshot document() const;
std::size_t old_index() const;
std::size_t new_index() const;
-
- private:
- friend class FirestoreInternal;
-
- static bool Initialize(App* app);
- static void Terminate(App* app);
};
} // namespace firestore
diff --git a/firestore/src/android/document_change_type_android.cc b/firestore/src/android/document_change_type_android.cc
index 2cd87eeb4a..90ae7c4eae 100644
--- a/firestore/src/android/document_change_type_android.cc
+++ b/firestore/src/android/document_change_type_android.cc
@@ -1,85 +1,41 @@
#include "firestore/src/android/document_change_type_android.h"
-#include "app/src/util_android.h"
+#include "../include/firebase/firestore/document_change.h"
+#include "app/src/assert.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
+namespace {
-using Type = DocumentChange::Type;
-
-// clang-format off
-#define DOCUMENT_CHANGE_TYPE_METHODS(X) X(Name, "name", "()Ljava/lang/String;")
-#define DOCUMENT_CHANGE_TYPE_FIELDS(X) \
- X(Added, "ADDED", "Lcom/google/firebase/firestore/DocumentChange$Type;", \
- util::kFieldTypeStatic), \
- X(Modified, "MODIFIED", \
- "Lcom/google/firebase/firestore/DocumentChange$Type;", \
- util::kFieldTypeStatic), \
- X(Removed, "REMOVED", "Lcom/google/firebase/firestore/DocumentChange$Type;", \
- util::kFieldTypeStatic)
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(document_change_type, DOCUMENT_CHANGE_TYPE_METHODS,
- DOCUMENT_CHANGE_TYPE_FIELDS)
-METHOD_LOOKUP_DEFINITION(document_change_type,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/DocumentChange$Type",
- DOCUMENT_CHANGE_TYPE_METHODS,
- DOCUMENT_CHANGE_TYPE_FIELDS)
-
-std::map* DocumentChangeTypeInternal::cpp_enum_to_java_ =
- nullptr;
+using jni::Env;
+using jni::Method;
+using jni::Object;
-/* static */
-Type DocumentChangeTypeInternal::JavaDocumentChangeTypeToDocumentChangeType(
- JNIEnv* env, jobject type) {
- for (const auto& kv : *cpp_enum_to_java_) {
- if (env->IsSameObject(type, kv.second)) {
- return kv.first;
- }
- }
- FIREBASE_ASSERT_MESSAGE(false, "Unknown DocumentChange type.");
- return Type::kAdded;
-}
+using Type = DocumentChange::Type;
-/* static */
-bool DocumentChangeTypeInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = document_change_type::CacheMethodIds(env, activity) &&
- document_change_type::CacheFieldIds(env, activity);
- util::CheckAndClearJniExceptions(env);
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/DocumentChange$Type";
+Method kOrdinal("ordinal", "()I");
- // Cache Java enum values.
- cpp_enum_to_java_ = new std::map();
- const auto add_enum = [env](Type type, document_change_type::Field field) {
- jobject value =
- env->GetStaticObjectField(document_change_type::GetClass(),
- document_change_type::GetFieldId(field));
- (*cpp_enum_to_java_)[type] = env->NewGlobalRef(value);
- env->DeleteLocalRef(value);
- util::CheckAndClearJniExceptions(env);
- };
- add_enum(Type::kAdded, document_change_type::kAdded);
- add_enum(Type::kModified, document_change_type::kModified);
- add_enum(Type::kRemoved, document_change_type::kRemoved);
+} // namespace
- return result;
+void DocumentChangeTypeInternal::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kClass, kOrdinal);
}
-/* static */
-void DocumentChangeTypeInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- document_change_type::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
+Type DocumentChangeTypeInternal::GetType(Env& env) const {
+ static constexpr int32_t kMinType = static_cast(Type::kAdded);
+ static constexpr int32_t kMaxType = static_cast(Type::kRemoved);
- // Uncache Java enum values.
- for (auto& kv : *cpp_enum_to_java_) {
- env->DeleteGlobalRef(kv.second);
+ int32_t ordinal = env.Call(*this, kOrdinal);
+ if (ordinal >= kMinType && ordinal <= kMaxType) {
+ return static_cast(ordinal);
+ } else {
+ FIREBASE_ASSERT_MESSAGE(false, "Unknown DocumentChange type.");
+ return Type::kAdded;
}
- util::CheckAndClearJniExceptions(env);
- delete cpp_enum_to_java_;
- cpp_enum_to_java_ = nullptr;
}
} // namespace firestore
diff --git a/firestore/src/android/document_change_type_android.h b/firestore/src/android/document_change_type_android.h
index 786885913b..cba99b531d 100644
--- a/firestore/src/android/document_change_type_android.h
+++ b/firestore/src/android/document_change_type_android.h
@@ -1,28 +1,20 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DOCUMENT_CHANGE_TYPE_ANDROID_H_
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DOCUMENT_CHANGE_TYPE_ANDROID_H_
-#include
-
-#include
-
-#include "app/src/include/firebase/app.h"
#include "firestore/src/include/firebase/firestore/document_change.h"
+#include "firestore/src/jni/jni_fwd.h"
+#include "firestore/src/jni/object.h"
namespace firebase {
namespace firestore {
-class DocumentChangeTypeInternal {
+class DocumentChangeTypeInternal : public jni::Object {
public:
- static DocumentChange::Type JavaDocumentChangeTypeToDocumentChangeType(
- JNIEnv* env, jobject type);
-
- private:
- friend class FirestoreInternal;
+ using jni::Object::Object;
- static bool Initialize(App* app);
- static void Terminate(App* app);
+ static void Initialize(jni::Loader& loader);
- static std::map* cpp_enum_to_java_;
+ DocumentChange::Type GetType(jni::Env& env) const;
};
} // namespace firestore
diff --git a/firestore/src/android/document_reference_android.cc b/firestore/src/android/document_reference_android.cc
index cb51943ad9..5cf3c26620 100644
--- a/firestore/src/android/document_reference_android.cc
+++ b/firestore/src/android/document_reference_android.cc
@@ -15,42 +15,60 @@
#include "firestore/src/android/source_android.h"
#include "firestore/src/android/util_android.h"
#include "firestore/src/include/firebase/firestore.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
-
-// clang-format off
-#define DOCUMENT_REFERENCE_METHODS(X) \
- X(GetId, "getId", "()Ljava/lang/String;"), \
- X(GetPath, "getPath", "()Ljava/lang/String;"), \
- X(GetParent, "getParent", \
- "()Lcom/google/firebase/firestore/CollectionReference;"), \
- X(Collection, "collection", "(Ljava/lang/String;)" \
- "Lcom/google/firebase/firestore/CollectionReference;"), \
- X(Get, "get", \
- "(Lcom/google/firebase/firestore/Source;)" \
- "Lcom/google/android/gms/tasks/Task;"), \
- X(Set, "set", \
- "(Ljava/lang/Object;Lcom/google/firebase/firestore/SetOptions;)" \
- "Lcom/google/android/gms/tasks/Task;"), \
- X(Update, "update", \
- "(Ljava/util/Map;)Lcom/google/android/gms/tasks/Task;"), \
- X(UpdateVarargs, "update", \
- "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;" \
- "[Ljava/lang/Object;)Lcom/google/android/gms/tasks/Task;"), \
- X(Delete, "delete", "()Lcom/google/android/gms/tasks/Task;"), \
- X(AddSnapshotListener, "addSnapshotListener", \
- "(Ljava/util/concurrent/Executor;" \
- "Lcom/google/firebase/firestore/MetadataChanges;" \
- "Lcom/google/firebase/firestore/EventListener;)" \
- "Lcom/google/firebase/firestore/ListenerRegistration;")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(document_reference, DOCUMENT_REFERENCE_METHODS)
-METHOD_LOOKUP_DEFINITION(document_reference,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/DocumentReference",
- DOCUMENT_REFERENCE_METHODS)
+namespace {
+
+using jni::Class;
+using jni::Env;
+using jni::Local;
+using jni::Method;
+using jni::Object;
+using jni::String;
+
+constexpr char kClassName[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/DocumentReference";
+jclass clazz = nullptr;
+
+Method kGetId("getId", "()Ljava/lang/String;");
+Method kGetPath("getPath", "()Ljava/lang/String;");
+Method kGetParent(
+ "getParent", "()Lcom/google/firebase/firestore/CollectionReference;");
+Method kCollection(
+ "collection",
+ "(Ljava/lang/String;)"
+ "Lcom/google/firebase/firestore/CollectionReference;");
+Method kGet("get",
+ "(Lcom/google/firebase/firestore/Source;)"
+ "Lcom/google/android/gms/tasks/Task;");
+Method kSet(
+ "set",
+ "(Ljava/lang/Object;Lcom/google/firebase/firestore/SetOptions;)"
+ "Lcom/google/android/gms/tasks/Task;");
+Method kUpdate("update",
+ "(Ljava/util/Map;)Lcom/google/android/gms/tasks/Task;");
+Method kUpdateVarargs(
+ "update",
+ "(Lcom/google/firebase/firestore/FieldPath;Ljava/lang/Object;"
+ "[Ljava/lang/Object;)Lcom/google/android/gms/tasks/Task;");
+Method kDelete("delete", "()Lcom/google/android/gms/tasks/Task;");
+Method kAddSnapshotListener(
+ "addSnapshotListener",
+ "(Ljava/util/concurrent/Executor;"
+ "Lcom/google/firebase/firestore/MetadataChanges;"
+ "Lcom/google/firebase/firestore/EventListener;)"
+ "Lcom/google/firebase/firestore/ListenerRegistration;");
+
+} // namespace
+
+void DocumentReferenceInternal::Initialize(jni::Loader& loader) {
+ clazz = loader.LoadClass(kClassName);
+ loader.LoadAll(kGetId, kGetPath, kGetParent, kCollection, kGet, kSet, kUpdate,
+ kUpdateVarargs, kDelete, kAddSnapshotListener);
+}
Firestore* DocumentReferenceInternal::firestore() {
FIREBASE_ASSERT(firestore_->firestore_public() != nullptr);
@@ -58,106 +76,56 @@ Firestore* DocumentReferenceInternal::firestore() {
}
const std::string& DocumentReferenceInternal::id() const {
- if (!cached_id_.empty()) {
- return cached_id_;
+ if (cached_id_.empty()) {
+ Env env = GetEnv();
+ cached_id_ = env.Call(obj_, kGetId).ToString(env);
}
-
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring id = static_cast(env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kGetId)));
- cached_id_ = util::JniStringToString(env, id);
- CheckAndClearJniExceptions(env);
-
return cached_id_;
}
const std::string& DocumentReferenceInternal::path() const {
- if (!cached_path_.empty()) {
- return cached_path_;
+ if (cached_path_.empty()) {
+ Env env = GetEnv();
+ cached_path_ = env.Call(obj_, kGetPath).ToString(env);
}
-
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring path = static_cast(env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kGetPath)));
- cached_path_ = util::JniStringToString(env, path);
- CheckAndClearJniExceptions(env);
-
return cached_path_;
}
CollectionReference DocumentReferenceInternal::Parent() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject parent = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kGetParent));
- CollectionReferenceInternal* internal =
- new CollectionReferenceInternal{firestore_, parent};
- env->DeleteLocalRef(parent);
- CheckAndClearJniExceptions(env);
- return CollectionReference(internal);
+ Env env = GetEnv();
+ Local parent = env.Call(obj_, kGetParent);
+ return firestore_->NewCollectionReference(env, parent);
}
CollectionReference DocumentReferenceInternal::Collection(
const std::string& collection_path) {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring path_string = env->NewStringUTF(collection_path.c_str());
- jobject collection = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kCollection),
- path_string);
- env->DeleteLocalRef(path_string);
- CheckAndClearJniExceptions(env);
- CollectionReferenceInternal* internal =
- new CollectionReferenceInternal{firestore_, collection};
- env->DeleteLocalRef(collection);
- CheckAndClearJniExceptions(env);
- return CollectionReference(internal);
+ Env env = GetEnv();
+ Local java_path = env.NewStringUtf(collection_path);
+ Local collection = env.Call(obj_, kCollection, java_path);
+ return firestore_->NewCollectionReference(env, collection);
}
Future DocumentReferenceInternal::Get(Source source) {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject task = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kGet),
- SourceInternal::ToJavaObject(env, source));
- CheckAndClearJniExceptions(env);
-
- auto promise = promises_.MakePromise();
- promise.RegisterForTask(DocumentReferenceFn::kGet, task);
- env->DeleteLocalRef(task);
- CheckAndClearJniExceptions(env);
- return promise.GetFuture();
+ Env env = GetEnv();
+ Local java_source = SourceInternal::Create(env, source);
+ Local task = env.Call(obj_, kGet, java_source);
+ return promises_.NewFuture(env, AsyncFn::kGet, task);
}
Future DocumentReferenceInternal::Set(const MapFieldValue& data,
const SetOptions& options) {
+ Env env = GetEnv();
FieldValueInternal map_value(data);
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject java_options = SetOptionsInternal::ToJavaObject(env, options);
- CheckAndClearJniExceptions(env);
- jobject task = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kSet),
- map_value.java_object(), java_options);
- env->DeleteLocalRef(java_options);
- CheckAndClearJniExceptions(env);
-
- auto promise = promises_.MakePromise();
- promise.RegisterForTask(DocumentReferenceFn::kSet, task);
- env->DeleteLocalRef(task);
- CheckAndClearJniExceptions(env);
- return promise.GetFuture();
+ Local java_options = SetOptionsInternal::Create(env, options);
+ Local task = env.Call(obj_, kSet, map_value, java_options);
+ return promises_.NewFuture(env, AsyncFn::kSet, task);
}
Future DocumentReferenceInternal::Update(const MapFieldValue& data) {
+ Env env = GetEnv();
FieldValueInternal map_value(data);
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject task = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kUpdate),
- map_value.java_object());
- CheckAndClearJniExceptions(env);
-
- auto promise = promises_.MakePromise();
- promise.RegisterForTask(DocumentReferenceFn::kUpdate, task);
- env->DeleteLocalRef(task);
- CheckAndClearJniExceptions(env);
- return promise.GetFuture();
+ Local task = env.Call(obj_, kUpdate, map_value);
+ return promises_.NewFuture(env, AsyncFn::kUpdate, task);
}
Future DocumentReferenceInternal::Update(const MapFieldPathValue& data) {
@@ -165,48 +133,26 @@ Future DocumentReferenceInternal::Update(const MapFieldPathValue& data) {
return Update(MapFieldValue{});
}
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- auto iter = data.begin();
- jobject first_field = FieldPathConverter::ToJavaObject(env, iter->first);
- jobject first_value = iter->second.internal_->java_object();
- ++iter;
-
- // Make the varargs
- jobjectArray more_fields_and_values =
- MapFieldPathValueToJavaArray(firestore_, iter, data.end());
+ Env env = GetEnv();
+ UpdateFieldPathArgs args = MakeUpdateFieldPathArgs(env, data);
+ Local task = env.Call(obj_, kUpdateVarargs, args.first_field,
+ args.first_value, args.varargs);
- jobject task = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kUpdateVarargs),
- first_field, first_value, more_fields_and_values);
- env->DeleteLocalRef(first_field);
- env->DeleteLocalRef(more_fields_and_values);
- CheckAndClearJniExceptions(env);
-
- auto promise = promises_.MakePromise();
- promise.RegisterForTask(DocumentReferenceFn::kUpdate, task);
- env->DeleteLocalRef(task);
- CheckAndClearJniExceptions(env);
- return promise.GetFuture();
+ return promises_.NewFuture(env, AsyncFn::kUpdate, task);
}
Future DocumentReferenceInternal::Delete() {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject task = env->CallObjectMethod(
- obj_, document_reference::GetMethodId(document_reference::kDelete));
- CheckAndClearJniExceptions(env);
-
- auto promise = promises_.MakePromise();
- promise.RegisterForTask(DocumentReferenceFn::kDelete, task);
- env->DeleteLocalRef(task);
- CheckAndClearJniExceptions(env);
- return promise.GetFuture();
+ Env env = GetEnv();
+ Local task = env.Call(obj_, kDelete);
+ return promises_.NewFuture(env, AsyncFn::kDelete, task);
}
#if defined(FIREBASE_USE_STD_FUNCTION)
ListenerRegistration DocumentReferenceInternal::AddSnapshotListener(
MetadataChanges metadata_changes,
- std::function callback) {
+ std::function
+ callback) {
LambdaEventListener* listener =
new LambdaEventListener(firebase::Move(callback));
return AddSnapshotListener(metadata_changes, listener,
@@ -218,51 +164,22 @@ ListenerRegistration DocumentReferenceInternal::AddSnapshotListener(
ListenerRegistration DocumentReferenceInternal::AddSnapshotListener(
MetadataChanges metadata_changes, EventListener* listener,
bool passing_listener_ownership) {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
-
- // Create listener.
- jobject java_listener =
- EventListenerInternal::EventListenerToJavaEventListener(env, firestore_,
- listener);
- jobject java_metadata =
- MetadataChangesInternal::ToJavaObject(env, metadata_changes);
-
- // Register listener.
- jobject java_registration = env->CallObjectMethod(
- obj_,
- document_reference::GetMethodId(document_reference::kAddSnapshotListener),
- firestore_->user_callback_executor(), java_metadata, java_listener);
- env->DeleteLocalRef(java_listener);
- CheckAndClearJniExceptions(env);
-
- // Wrapping
- ListenerRegistrationInternal* registration = new ListenerRegistrationInternal{
- firestore_, listener, passing_listener_ownership, java_registration};
- env->DeleteLocalRef(java_registration);
-
- return ListenerRegistration{registration};
+ Env env = GetEnv();
+ Local java_metadata =
+ MetadataChangesInternal::Create(env, metadata_changes);
+ Local java_listener =
+ EventListenerInternal::Create(env, firestore_, listener);
+
+ Local java_registration =
+ env.Call(obj_, kAddSnapshotListener, firestore_->user_callback_executor(),
+ java_metadata, java_listener);
+
+ if (!env.ok() || !java_registration) return {};
+ return ListenerRegistration(new ListenerRegistrationInternal(
+ firestore_, listener, passing_listener_ownership, java_registration));
}
-/* static */
-jclass DocumentReferenceInternal::GetClass() {
- return document_reference::GetClass();
-}
-
-/* static */
-bool DocumentReferenceInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = document_reference::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void DocumentReferenceInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- document_reference::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
-}
+Class DocumentReferenceInternal::GetClass() { return Class(clazz); }
} // namespace firestore
} // namespace firebase
diff --git a/firestore/src/android/document_reference_android.h b/firestore/src/android/document_reference_android.h
index 5fa010e4ea..65d72c3a3b 100644
--- a/firestore/src/android/document_reference_android.h
+++ b/firestore/src/android/document_reference_android.h
@@ -10,29 +10,30 @@
#include "firestore/src/android/promise_factory_android.h"
#include "firestore/src/android/wrapper.h"
#include "firestore/src/include/firebase/firestore/collection_reference.h"
+#include "firestore/src/jni/jni_fwd.h"
namespace firebase {
namespace firestore {
class Firestore;
-// Each API of DocumentReference that returns a Future needs to define an enum
-// value here. For example, a Future-returning method Foo() relies on the enum
-// value kFoo. The enum values are used to identify and manage Future in the
-// Firestore Future manager.
-enum class DocumentReferenceFn {
- kGet = 0,
- kSet,
- kUpdate,
- kDelete,
- kCount, // Must be the last enum value.
-};
-
// This is the Android implementation of DocumentReference.
class DocumentReferenceInternal : public Wrapper {
public:
using ApiType = DocumentReference;
+ // Each API of DocumentReference that returns a Future needs to define an enum
+ // value here. For example, a Future-returning method Foo() relies on the enum
+ // value kFoo. The enum values are used to identify and manage Future in the
+ // Firestore Future manager.
+ enum class AsyncFn {
+ kGet = 0,
+ kSet,
+ kUpdate,
+ kDelete,
+ kCount, // Must be the last enum value.
+ };
+
DocumentReferenceInternal(FirestoreInternal* firestore, jobject object)
: Wrapper(firestore, object), promises_(firestore) {}
@@ -145,7 +146,8 @@ class DocumentReferenceInternal : public Wrapper {
*/
ListenerRegistration AddSnapshotListener(
MetadataChanges metadata_changes,
- std::function callback);
+ std::function
+ callback);
#endif // defined(FIREBASE_USE_STD_FUNCTION)
/**
@@ -170,15 +172,14 @@ class DocumentReferenceInternal : public Wrapper {
bool passing_listener_ownership = false);
/** @brief Gets the class object of Java DocumentReference class. */
- static jclass GetClass();
+ static jni::Class GetClass();
private:
friend class FirestoreInternal;
- static bool Initialize(App* app);
- static void Terminate(App* app);
+ static void Initialize(jni::Loader& loader);
- PromiseFactory promises_;
+ PromiseFactory promises_;
// Below are cached call results.
mutable std::string cached_id_;
diff --git a/firestore/src/android/document_snapshot_android.cc b/firestore/src/android/document_snapshot_android.cc
index 54ab29abd8..0d2d05116c 100644
--- a/firestore/src/android/document_snapshot_android.cc
+++ b/firestore/src/android/document_snapshot_android.cc
@@ -4,44 +4,53 @@
#include
-#include "app/src/util_android.h"
#include "firestore/src/android/document_reference_android.h"
#include "firestore/src/android/field_path_android.h"
#include "firestore/src/android/field_value_android.h"
#include "firestore/src/android/server_timestamp_behavior_android.h"
#include "firestore/src/android/snapshot_metadata_android.h"
-#include "firestore/src/android/util_android.h"
#include "firestore/src/include/firebase/firestore.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
namespace firebase {
namespace firestore {
+namespace {
+
+using jni::Env;
+using jni::Local;
+using jni::Map;
+using jni::Method;
+using jni::Object;
+using jni::String;
using ServerTimestampBehavior = DocumentSnapshot::ServerTimestampBehavior;
-// clang-format off
-#define DOCUMENT_SNAPSHOT_METHODS(X) \
- X(GetId, "getId", "()Ljava/lang/String;"), \
- X(GetReference, "getReference", \
- "()Lcom/google/firebase/firestore/DocumentReference;"), \
- X(GetMetadata, "getMetadata", \
- "()Lcom/google/firebase/firestore/SnapshotMetadata;"), \
- X(Exists, "exists", "()Z"), \
- X(GetData, "getData", \
- "(Lcom/google/firebase/firestore/DocumentSnapshot$" \
- "ServerTimestampBehavior;)Ljava/util/Map;"), \
- X(Contains, "contains", \
- "(Lcom/google/firebase/firestore/FieldPath;)Z"), \
- X(Get, "get", \
- "(Lcom/google/firebase/firestore/FieldPath;" \
- "Lcom/google/firebase/firestore/DocumentSnapshot$" \
- "ServerTimestampBehavior;)Ljava/lang/Object;")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(document_snapshot, DOCUMENT_SNAPSHOT_METHODS)
-METHOD_LOOKUP_DEFINITION(document_snapshot,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/DocumentSnapshot",
- DOCUMENT_SNAPSHOT_METHODS)
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/DocumentSnapshot";
+
+Method kGetId("getId", "()Ljava/lang/String;");
+Method kGetReference(
+ "getReference", "()Lcom/google/firebase/firestore/DocumentReference;");
+Method kGetMetadata(
+ "getMetadata", "()Lcom/google/firebase/firestore/SnapshotMetadata;");
+Method kExists("exists", "()Z");
+Method kGetData("getData",
+ "(Lcom/google/firebase/firestore/DocumentSnapshot$"
+ "ServerTimestampBehavior;)Ljava/util/Map;");
+Method kContains("contains",
+ "(Lcom/google/firebase/firestore/FieldPath;)Z");
+Method kGet("get",
+ "(Lcom/google/firebase/firestore/FieldPath;"
+ "Lcom/google/firebase/firestore/DocumentSnapshot$"
+ "ServerTimestampBehavior;)Ljava/lang/Object;");
+
+} // namespace
+
+void DocumentSnapshotInternal::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kClass, kGetId, kGetReference, kGetMetadata, kExists,
+ kGetData, kContains, kGet);
+}
Firestore* DocumentSnapshotInternal::firestore() const {
FIREBASE_ASSERT(firestore_->firestore_public() != nullptr);
@@ -49,110 +58,56 @@ Firestore* DocumentSnapshotInternal::firestore() const {
}
const std::string& DocumentSnapshotInternal::id() const {
- if (!cached_id_.empty()) {
- return cached_id_;
+ if (cached_id_.empty()) {
+ Env env = GetEnv();
+ cached_id_ = env.Call(obj_, kGetId).ToString(env);
}
-
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jstring id = static_cast(env->CallObjectMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kGetId)));
- cached_id_ = util::JniStringToString(env, id);
-
- CheckAndClearJniExceptions(env);
return cached_id_;
}
DocumentReference DocumentSnapshotInternal::reference() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject reference = env->CallObjectMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kGetReference));
- DocumentReferenceInternal* internal =
- new DocumentReferenceInternal{firestore_, reference};
- env->DeleteLocalRef(reference);
-
- CheckAndClearJniExceptions(env);
- return DocumentReference{internal};
+ Env env = GetEnv();
+ Local reference = env.Call(obj_, kGetReference);
+ return firestore_->NewDocumentReference(env, reference);
}
SnapshotMetadata DocumentSnapshotInternal::metadata() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject metadata = env->CallObjectMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kGetMetadata));
- SnapshotMetadata result =
- SnapshotMetadataInternal::JavaSnapshotMetadataToSnapshotMetadata(
- env, metadata);
-
- CheckAndClearJniExceptions(env);
- return result;
+ Env env = GetEnv();
+ auto java_metadata = env.Call(obj_, kGetMetadata);
+ return java_metadata.ToPublic(env);
}
bool DocumentSnapshotInternal::exists() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jboolean exists = env->CallBooleanMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kExists));
-
- CheckAndClearJniExceptions(env);
- return static_cast(exists);
+ Env env = GetEnv();
+ return env.Call(obj_, kExists);
}
MapFieldValue DocumentSnapshotInternal::GetData(
ServerTimestampBehavior stb) const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject stb_enum = ServerTimestampBehaviorInternal::ToJavaObject(env, stb);
-
- jobject map_value = env->CallObjectMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kGetData),
- stb_enum);
- CheckAndClearJniExceptions(env);
+ Env env = GetEnv();
+ Local java_stb = ServerTimestampBehaviorInternal::Create(env, stb);
+ Local java_data = env.Call(obj_, kGetData, java_stb);
- FieldValueInternal value(firestore_, map_value);
- env->DeleteLocalRef(map_value);
+ FieldValueInternal value(firestore_, java_data.get());
return value.map_value();
}
FieldValue DocumentSnapshotInternal::Get(const FieldPath& field,
ServerTimestampBehavior stb) const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject field_path = FieldPathConverter::ToJavaObject(env, field);
+ Env env = GetEnv();
+ Local java_field = FieldPathConverter::Create(env, field);
// Android returns null for both null fields and nonexistent fields, so first
// use contains() to check if the field exists.
- jboolean contains_field = env->CallBooleanMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kContains),
- field_path);
- CheckAndClearJniExceptions(env);
+ bool contains_field = env.Call(obj_, kContains, java_field);
if (!contains_field) {
- env->DeleteLocalRef(field_path);
return FieldValue();
- } else {
- jobject stb_enum = ServerTimestampBehaviorInternal::ToJavaObject(env, stb);
-
- jobject field_value = env->CallObjectMethod(
- obj_, document_snapshot::GetMethodId(document_snapshot::kGet),
- field_path, stb_enum);
- CheckAndClearJniExceptions(env);
- env->DeleteLocalRef(field_path);
-
- FieldValue result{new FieldValueInternal{firestore_, field_value}};
- env->DeleteLocalRef(field_value);
- return result;
}
-}
-/* static */
-bool DocumentSnapshotInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = document_snapshot::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
-}
+ Local java_stb = ServerTimestampBehaviorInternal::Create(env, stb);
+ Local field_value = env.Call(obj_, kGet, java_field, java_stb);
-/* static */
-void DocumentSnapshotInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- document_snapshot::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
+ return FieldValue(new FieldValueInternal(firestore_, field_value.get()));
}
} // namespace firestore
diff --git a/firestore/src/android/document_snapshot_android.h b/firestore/src/android/document_snapshot_android.h
index 30563f3726..5d3f10b808 100644
--- a/firestore/src/android/document_snapshot_android.h
+++ b/firestore/src/android/document_snapshot_android.h
@@ -1,10 +1,8 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DOCUMENT_SNAPSHOT_ANDROID_H_
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_DOCUMENT_SNAPSHOT_ANDROID_H_
-#include
#include
-#include "app/src/include/firebase/app.h"
#include "firestore/src/android/firestore_android.h"
#include "firestore/src/android/wrapper.h"
#include "firestore/src/include/firebase/firestore/document_reference.h"
@@ -21,6 +19,8 @@ class DocumentSnapshotInternal : public Wrapper {
using ApiType = DocumentSnapshot;
using Wrapper::Wrapper;
+ static void Initialize(jni::Loader& loader);
+
~DocumentSnapshotInternal() override {}
/** Gets the Firestore instance associated with this document snapshot. */
@@ -46,12 +46,6 @@ class DocumentSnapshotInternal : public Wrapper {
DocumentSnapshot::ServerTimestampBehavior stb) const;
private:
- friend class FirestoreInternal;
-
- static bool Initialize(App* app);
- static void Terminate(App* app);
-
- // Below are cached call results.
mutable std::string cached_id_;
};
diff --git a/firestore/src/android/event_listener_android.cc b/firestore/src/android/event_listener_android.cc
index 17d9e0d081..16986e5a95 100644
--- a/firestore/src/android/event_listener_android.cc
+++ b/firestore/src/android/event_listener_android.cc
@@ -7,196 +7,150 @@
#include "app/src/include/firebase/internal/common.h"
#include "app/src/util_android.h"
#include "firestore/src/android/document_snapshot_android.h"
-#include "firestore/src/android/firebase_firestore_exception_android.h"
+#include "firestore/src/android/exception_android.h"
#include "firestore/src/android/query_snapshot_android.h"
#include "firestore/src/android/util_android.h"
+#include "firestore/src/common/util.h"
#include "firestore/src/include/firebase/firestore/query_snapshot.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
#include "firebase/firestore/firestore_errors.h"
namespace firebase {
namespace firestore {
+namespace {
-#define CPP_EVENT_LISTENER_METHODS(X) \
- X(DiscardPointers, "discardPointers", "()V")
-METHOD_LOOKUP_DECLARATION(cpp_event_listener, CPP_EVENT_LISTENER_METHODS)
-METHOD_LOOKUP_DEFINITION(
- cpp_event_listener,
- "com/google/firebase/firestore/internal/cpp/CppEventListener",
- CPP_EVENT_LISTENER_METHODS)
-
-#define DOCUMENT_EVENT_LISTENER_METHODS(X) X(Constructor, "", "(JJ)V")
-METHOD_LOOKUP_DECLARATION(document_event_listener,
- DOCUMENT_EVENT_LISTENER_METHODS)
-METHOD_LOOKUP_DEFINITION(
- document_event_listener,
- "com/google/firebase/firestore/internal/cpp/DocumentEventListener",
- DOCUMENT_EVENT_LISTENER_METHODS)
-
-#define QUERY_EVENT_LISTENER_METHODS(X) X(Constructor, "", "(JJ)V")
-METHOD_LOOKUP_DECLARATION(query_event_listener, QUERY_EVENT_LISTENER_METHODS)
-METHOD_LOOKUP_DEFINITION(
- query_event_listener,
- "com/google/firebase/firestore/internal/cpp/QueryEventListener",
- QUERY_EVENT_LISTENER_METHODS)
-
-#define VOID_EVENT_LISTENER_METHODS(X) X(Constructor, "", "(J)V")
-METHOD_LOOKUP_DECLARATION(void_event_listener, VOID_EVENT_LISTENER_METHODS)
-METHOD_LOOKUP_DEFINITION(
- void_event_listener,
- "com/google/firebase/firestore/internal/cpp/VoidEventListener",
- VOID_EVENT_LISTENER_METHODS)
+using jni::Constructor;
+using jni::Env;
+using jni::Local;
+using jni::Method;
+using jni::Object;
+
+constexpr char kCppEventListenerClassName[] =
+ "com/google/firebase/firestore/internal/cpp/CppEventListener";
+Method kDiscardPointers("discardPointers", "()V");
+
+constexpr char kDocumentEventListenerClassName[] =
+ "com/google/firebase/firestore/internal/cpp/DocumentEventListener";
+Constructor kNewDocumentEventListener("(JJ)V");
+
+constexpr char kQueryEventListenerClassName[] =
+ "com/google/firebase/firestore/internal/cpp/QueryEventListener";
+Constructor kNewQueryEventListener("(JJ)V");
+
+constexpr char kVoidEventListenerClassName[] =
+ "com/google/firebase/firestore/internal/cpp/VoidEventListener";
+Constructor kNewVoidEventListener("(J)V");
+
+} // namespace
/* static */
+void EventListenerInternal::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kCppEventListenerClassName, kDiscardPointers);
+
+ static const JNINativeMethod kDocumentEventListenerNatives[] = {
+ {"nativeOnEvent",
+ "(JJLjava/lang/Object;Lcom/google/firebase/firestore/"
+ "FirebaseFirestoreException;)V",
+ reinterpret_cast(
+ &EventListenerInternal::DocumentEventListenerNativeOnEvent)}};
+ loader.LoadClass(kDocumentEventListenerClassName, kNewDocumentEventListener);
+ loader.RegisterNatives(kDocumentEventListenerNatives,
+ FIREBASE_ARRAYSIZE(kDocumentEventListenerNatives));
+
+ static const JNINativeMethod kQueryEventListenerNatives[] = {
+ {"nativeOnEvent",
+ "(JJLjava/lang/Object;Lcom/google/firebase/firestore/"
+ "FirebaseFirestoreException;)V",
+ reinterpret_cast(
+ &EventListenerInternal::QueryEventListenerNativeOnEvent)}};
+ loader.LoadClass(kQueryEventListenerClassName, kNewQueryEventListener);
+ loader.RegisterNatives(kQueryEventListenerNatives,
+ FIREBASE_ARRAYSIZE(kQueryEventListenerNatives));
+
+ static const JNINativeMethod kVoidEventListenerNatives[] = {
+ {"nativeOnEvent", "(J)V",
+ reinterpret_cast(
+ &EventListenerInternal::VoidEventListenerNativeOnEvent)}};
+ loader.LoadClass(kVoidEventListenerClassName, kNewVoidEventListener);
+ loader.RegisterNatives(kVoidEventListenerNatives,
+ FIREBASE_ARRAYSIZE(kVoidEventListenerNatives));
+}
+
void EventListenerInternal::DocumentEventListenerNativeOnEvent(
- JNIEnv* env, jclass clazz, jlong firestore_ptr, jlong listener_ptr,
- jobject value, jobject error) {
+ JNIEnv* raw_env, jclass, jlong firestore_ptr, jlong listener_ptr,
+ jobject value, jobject raw_error) {
if (firestore_ptr == 0 || listener_ptr == 0) {
return;
}
- EventListener* listener =
+ auto* listener =
reinterpret_cast*>(listener_ptr);
- Error error_code =
- FirebaseFirestoreExceptionInternal::ToErrorCode(env, error);
+ auto* firestore = reinterpret_cast(firestore_ptr);
+
+ Env env(raw_env);
+ Object error(raw_error);
+ Error error_code = ExceptionInternal::GetErrorCode(env, error);
+ std::string error_message = ExceptionInternal::ToString(env, error);
if (error_code != Error::kErrorOk) {
- listener->OnEvent(DocumentSnapshot{}, error_code);
+ listener->OnEvent({}, error_code, error_message);
return;
}
- FirestoreInternal* firestore =
- reinterpret_cast(firestore_ptr);
- DocumentSnapshot snapshot(new DocumentSnapshotInternal{firestore, value});
- listener->OnEvent(snapshot, error_code);
+ auto snapshot = firestore->NewDocumentSnapshot(env, Object(value));
+ listener->OnEvent(snapshot, error_code, error_message);
}
/* static */
void EventListenerInternal::QueryEventListenerNativeOnEvent(
- JNIEnv* env, jclass clazz, jlong firestore_ptr, jlong listener_ptr,
- jobject value, jobject error) {
+ JNIEnv* raw_env, jclass, jlong firestore_ptr, jlong listener_ptr,
+ jobject value, jobject raw_error) {
if (firestore_ptr == 0 || listener_ptr == 0) {
return;
}
- EventListener* listener =
+ auto* listener =
reinterpret_cast*>(listener_ptr);
- Error error_code =
- FirebaseFirestoreExceptionInternal::ToErrorCode(env, error);
+ auto* firestore = reinterpret_cast(firestore_ptr);
+
+ Env env(raw_env);
+ Object error(raw_error);
+ Error error_code = ExceptionInternal::GetErrorCode(env, error);
+ std::string error_message = ExceptionInternal::ToString(env, error);
if (error_code != Error::kErrorOk) {
- listener->OnEvent(QuerySnapshot{}, error_code);
+ listener->OnEvent({}, error_code, error_message);
return;
}
- FirestoreInternal* firestore =
- reinterpret_cast(firestore_ptr);
- QuerySnapshot snapshot(new QuerySnapshotInternal{firestore, value});
- listener->OnEvent(snapshot, error_code);
+ auto snapshot = firestore->NewQuerySnapshot(env, Object(value));
+ listener->OnEvent(snapshot, error_code, error_message);
}
/* static */
-void EventListenerInternal::VoidEventListenerNativeOnEvent(JNIEnv* env,
- jclass clazz,
+void EventListenerInternal::VoidEventListenerNativeOnEvent(JNIEnv*, jclass,
jlong listener_ptr) {
if (listener_ptr == 0) {
return;
}
- EventListener* listener =
- reinterpret_cast*>(listener_ptr);
-
- listener->OnEvent(Error::kErrorOk);
+ auto* listener = reinterpret_cast*>(listener_ptr);
+ listener->OnEvent(Error::kErrorOk, EmptyString());
}
-/* static */
-jobject EventListenerInternal::EventListenerToJavaEventListener(
- JNIEnv* env, FirestoreInternal* firestore,
+Local EventListenerInternal::Create(
+ Env& env, FirestoreInternal* firestore,
EventListener* listener) {
- jobject result = env->NewObject(document_event_listener::GetClass(),
- document_event_listener::GetMethodId(
- document_event_listener::kConstructor),
- reinterpret_cast(firestore),
- reinterpret_cast(listener));
- CheckAndClearJniExceptions(env);
- return result;
+ return env.New(kNewDocumentEventListener, reinterpret_cast(firestore),
+ reinterpret_cast(listener));
}
-/* static */
-jobject EventListenerInternal::EventListenerToJavaEventListener(
- JNIEnv* env, FirestoreInternal* firestore,
+Local EventListenerInternal::Create(
+ Env& env, FirestoreInternal* firestore,
EventListener* listener) {
- jobject result = env->NewObject(
- query_event_listener::GetClass(),
- query_event_listener::GetMethodId(query_event_listener::kConstructor),
- reinterpret_cast(firestore), reinterpret_cast(listener));
- CheckAndClearJniExceptions(env);
- return result;
+ return env.New(kNewQueryEventListener, reinterpret_cast(firestore),
+ reinterpret_cast(listener));
}
-/* static */
-jobject EventListenerInternal::EventListenerToJavaRunnable(
- JNIEnv* env, EventListener* listener) {
- jobject result = env->NewObject(
- void_event_listener::GetClass(),
- void_event_listener::GetMethodId(void_event_listener::kConstructor),
- reinterpret_cast(listener));
- CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-bool EventListenerInternal::InitializeEmbeddedClasses(
- App* app, const std::vector* embedded_files) {
- static const JNINativeMethod kDocumentEventListenerNatives[] = {
- {"nativeOnEvent",
- "(JJLjava/lang/Object;Lcom/google/firebase/firestore/"
- "FirebaseFirestoreException;)V",
- reinterpret_cast(
- &EventListenerInternal::DocumentEventListenerNativeOnEvent)}};
- static const JNINativeMethod kQueryEventListenerNatives[] = {
- {"nativeOnEvent",
- "(JJLjava/lang/Object;Lcom/google/firebase/firestore/"
- "FirebaseFirestoreException;)V",
- reinterpret_cast(
- &EventListenerInternal::QueryEventListenerNativeOnEvent)}};
- static const JNINativeMethod kVoidEventListenerNatives[] = {
- {"nativeOnEvent", "(J)V",
- reinterpret_cast(
- &EventListenerInternal::VoidEventListenerNativeOnEvent)}};
-
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result =
- // Cache classes
- cpp_event_listener::CacheClassFromFiles(env, activity, embedded_files) &&
- document_event_listener::CacheClassFromFiles(env, activity,
- embedded_files) &&
- query_event_listener::CacheClassFromFiles(env, activity,
- embedded_files) &&
- void_event_listener::CacheClassFromFiles(env, activity, embedded_files) &&
- // Cache method-ids
- cpp_event_listener::CacheMethodIds(env, activity) &&
- document_event_listener::CacheMethodIds(env, activity) &&
- query_event_listener::CacheMethodIds(env, activity) &&
- void_event_listener::CacheMethodIds(env, activity) &&
- // Register natives
- document_event_listener::RegisterNatives(
- env, kDocumentEventListenerNatives,
- FIREBASE_ARRAYSIZE(kDocumentEventListenerNatives)) &&
- query_event_listener::RegisterNatives(
- env, kQueryEventListenerNatives,
- FIREBASE_ARRAYSIZE(kQueryEventListenerNatives)) &&
- void_event_listener::RegisterNatives(
- env, kVoidEventListenerNatives,
- FIREBASE_ARRAYSIZE(kVoidEventListenerNatives));
- util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void EventListenerInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- // Release embedded classes.
- cpp_event_listener::ReleaseClass(env);
- document_event_listener::ReleaseClass(env);
- query_event_listener::ReleaseClass(env);
- void_event_listener::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
+Local EventListenerInternal::Create(Env& env,
+ EventListener* listener) {
+ return env.New(kNewVoidEventListener, reinterpret_cast(listener));
}
} // namespace firestore
diff --git a/firestore/src/android/event_listener_android.h b/firestore/src/android/event_listener_android.h
index 7907deba72..b0f1dcf7b0 100644
--- a/firestore/src/android/event_listener_android.h
+++ b/firestore/src/android/event_listener_android.h
@@ -1,18 +1,18 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_EVENT_LISTENER_ANDROID_H_
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_EVENT_LISTENER_ANDROID_H_
-#include
-
-#include "app/src/embedded_file.h"
#include "firestore/src/android/firestore_android.h"
#include "firestore/src/include/firebase/firestore/document_snapshot.h"
#include "firestore/src/include/firebase/firestore/event_listener.h"
+#include "firestore/src/jni/jni_fwd.h"
namespace firebase {
namespace firestore {
class EventListenerInternal {
public:
+ static void Initialize(jni::Loader& loader);
+
static void DocumentEventListenerNativeOnEvent(JNIEnv* env, jclass clazz,
jlong firestore_ptr,
jlong listener_ptr,
@@ -24,23 +24,27 @@ class EventListenerInternal {
static void VoidEventListenerNativeOnEvent(JNIEnv* env, jclass clazz,
jlong listener_ptr);
+ static jni::Local Create(
+ jni::Env& env, FirestoreInternal* firestore,
+ EventListener* listener);
+
static jobject EventListenerToJavaEventListener(
JNIEnv* env, FirestoreInternal* firestore,
EventListener* listener);
+ static jni::Local Create(jni::Env& env,
+ FirestoreInternal* firestore,
+ EventListener* listener);
+
static jobject EventListenerToJavaEventListener(
JNIEnv* env, FirestoreInternal* firestore,
EventListener* listener);
+ static jni::Local Create(jni::Env& env,
+ EventListener* listener);
+
static jobject EventListenerToJavaRunnable(JNIEnv* env,
EventListener* listener);
-
- private:
- friend class FirestoreInternal;
-
- static bool InitializeEmbeddedClasses(
- App* app, const std::vector* embedded_files);
- static void Terminate(App* app);
};
} // namespace firestore
diff --git a/firestore/src/android/exception_android.cc b/firestore/src/android/exception_android.cc
new file mode 100644
index 0000000000..afe5e7a85e
--- /dev/null
+++ b/firestore/src/android/exception_android.cc
@@ -0,0 +1,137 @@
+#include "firestore/src/android/exception_android.h"
+
+#include "app/src/util_android.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
+#include "firestore/src/jni/throwable.h"
+
+namespace firebase {
+namespace firestore {
+namespace {
+
+using jni::Constructor;
+using jni::Env;
+using jni::Local;
+using jni::Method;
+using jni::Object;
+using jni::StaticMethod;
+using jni::String;
+using jni::Throwable;
+
+// FirebaseFirestoreException
+constexpr char kFirestoreExceptionClassName[] = PROGUARD_KEEP_CLASS
+ "com/google/firebase/firestore/FirebaseFirestoreException";
+
+Constructor kNewFirestoreException(
+ "(Ljava/lang/String;"
+ "Lcom/google/firebase/firestore/FirebaseFirestoreException$Code;)V");
+Method kGetCode(
+ "getCode",
+ "()Lcom/google/firebase/firestore/FirebaseFirestoreException$Code;");
+
+jclass g_firestore_exception_class = nullptr;
+
+// FirebaseFirestoreException$Code
+constexpr char kCodeClassName[] = PROGUARD_KEEP_CLASS
+ "com/google/firebase/firestore/FirebaseFirestoreException$Code";
+
+Method kValue("value", "()I");
+StaticMethod kFromValue(
+ "fromValue",
+ "(I)Lcom/google/firebase/firestore/FirebaseFirestoreException$Code;");
+
+// IllegalStateException
+constexpr char kIllegalStateExceptionClassName[] =
+ PROGUARD_KEEP_CLASS "java/lang/IllegalStateException";
+Constructor kNewIllegalStateException("()V");
+
+jclass g_illegal_state_exception_class = nullptr;
+
+} // namespace
+
+/* static */
+void ExceptionInternal::Initialize(jni::Loader& loader) {
+ g_firestore_exception_class = loader.LoadClass(
+ kFirestoreExceptionClassName, kNewFirestoreException, kGetCode);
+
+ loader.LoadClass(kCodeClassName, kValue, kFromValue);
+
+ g_illegal_state_exception_class = loader.LoadClass(
+ kIllegalStateExceptionClassName, kNewIllegalStateException);
+}
+
+Error ExceptionInternal::GetErrorCode(Env& env, const Object& exception) {
+ if (!exception) {
+ return Error::kErrorOk;
+ }
+
+ if (IsIllegalStateException(env, exception)) {
+ // Some of the Precondition failure is thrown as IllegalStateException
+ // instead of a FirebaseFirestoreException. Convert those into a more
+ // meaningful code.
+ return Error::kErrorFailedPrecondition;
+ } else if (!IsFirestoreException(env, exception)) {
+ return Error::kErrorUnknown;
+ }
+
+ Local java_code = env.Call(exception, kGetCode);
+ int32_t code = env.Call(java_code, kValue);
+
+ if (code > Error::kErrorUnauthenticated || code < Error::kErrorOk) {
+ return Error::kErrorUnknown;
+ }
+ return static_cast(code);
+}
+
+std::string ExceptionInternal::ToString(Env& env, const Object& exception) {
+ return util::GetMessageFromException(env.get(), exception.get());
+}
+
+Local ExceptionInternal::Create(Env& env, Error code,
+ const std::string& message) {
+ if (code == Error::kErrorOk) {
+ return {};
+ }
+
+ Local java_message;
+ if (message.empty()) {
+ // FirebaseFirestoreException requires message to be non-empty. If the
+ // caller does not bother to give details, we assign an arbitrary message
+ // here.
+ java_message = env.NewStringUtf("Unknown Exception");
+ } else {
+ java_message = env.NewStringUtf(message);
+ }
+
+ Local java_code = env.Call(kFromValue, static_cast(code));
+ return env.New(kNewFirestoreException, java_message, java_code);
+}
+
+Local ExceptionInternal::Wrap(Env& env,
+ Local&& exception) {
+ if (IsFirestoreException(env, exception)) {
+ return Move(exception);
+ } else {
+ return Create(env, GetErrorCode(env, exception),
+ ToString(env, exception).c_str());
+ }
+}
+
+bool ExceptionInternal::IsFirestoreException(Env& env,
+ const Object& exception) {
+ return env.IsInstanceOf(exception, g_firestore_exception_class);
+}
+
+bool ExceptionInternal::IsIllegalStateException(Env& env,
+ const Object& exception) {
+ return env.IsInstanceOf(exception, g_illegal_state_exception_class);
+}
+
+bool ExceptionInternal::IsAnyExceptionThrownByFirestore(
+ Env& env, const Object& exception) {
+ return IsFirestoreException(env, exception) ||
+ IsIllegalStateException(env, exception);
+}
+
+} // namespace firestore
+} // namespace firebase
diff --git a/firestore/src/android/exception_android.h b/firestore/src/android/exception_android.h
new file mode 100644
index 0000000000..738e234e4d
--- /dev/null
+++ b/firestore/src/android/exception_android.h
@@ -0,0 +1,43 @@
+#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_EXCEPTION_ANDROID_H_
+#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_EXCEPTION_ANDROID_H_
+
+#include
+
+#include "app/src/include/firebase/app.h"
+#include "firestore/src/jni/jni_fwd.h"
+#include "firebase/firestore/firestore_errors.h"
+
+namespace firebase {
+namespace firestore {
+
+class ExceptionInternal {
+ public:
+ static void Initialize(jni::Loader& loader);
+
+ static Error GetErrorCode(jni::Env& env, const jni::Object& exception);
+ static std::string ToString(jni::Env& env, const jni::Object& exception);
+
+ static jni::Local Create(jni::Env& env, Error code,
+ const std::string& message);
+ static jni::Local Wrap(
+ jni::Env& env, jni::Local&& exception);
+
+ /** Returns true if the given object is a FirestoreException. */
+ static bool IsFirestoreException(jni::Env& env, const jni::Object& exception);
+
+ /** Returns true if the given object is an IllegalStateException. */
+ static bool IsIllegalStateException(jni::Env& env,
+ const jni::Object& exception);
+
+ /**
+ * Returns true if the given object is a FirestoreException or any other type
+ * of exception thrown by a Firestore API.
+ */
+ static bool IsAnyExceptionThrownByFirestore(jni::Env& env,
+ const jni::Object& exception);
+};
+
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_EXCEPTION_ANDROID_H_
diff --git a/firestore/src/android/field_path_android.cc b/firestore/src/android/field_path_android.cc
index dd35310139..2db98584ca 100644
--- a/firestore/src/android/field_path_android.cc
+++ b/firestore/src/android/field_path_android.cc
@@ -2,6 +2,9 @@
#include "app/src/util_android.h"
#include "firestore/src/android/util_android.h"
+#include "firestore/src/jni/array.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/loader.h"
#if defined(__ANDROID__)
#include "firestore/src/android/field_path_portable.h"
@@ -11,70 +14,44 @@
namespace firebase {
namespace firestore {
+namespace {
+
+using jni::Array;
+using jni::Env;
+using jni::Local;
+using jni::Object;
+using jni::StaticMethod;
+using jni::String;
+
+constexpr char kClass[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/FieldPath";
+StaticMethod kOf(
+ "of", "([Ljava/lang/String;)Lcom/google/firebase/firestore/FieldPath;");
+StaticMethod kDocumentId("documentId",
+ "()Lcom/google/firebase/firestore/FieldPath;");
+
+} // namespace
+
+void FieldPathConverter::Initialize(jni::Loader& loader) {
+ loader.LoadClass(kClass, kOf, kDocumentId);
+}
-// clang-format off
-#define FIELD_PATH_METHODS(X) \
- X(Of, "of", \
- "([Ljava/lang/String;)Lcom/google/firebase/firestore/FieldPath;", \
- firebase::util::kMethodTypeStatic), \
- X(DocumentId, "documentId", \
- "()Lcom/google/firebase/firestore/FieldPath;", \
- firebase::util::kMethodTypeStatic)
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(field_path, FIELD_PATH_METHODS)
-METHOD_LOOKUP_DEFINITION(field_path,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/FieldPath",
- FIELD_PATH_METHODS)
+Local FieldPathConverter::Create(Env& env, const FieldPath& path) {
+ FieldPath::FieldPathInternal& internal = *path.internal_;
-/* static */
-jobject FieldPathConverter::ToJavaObject(JNIEnv* env, const FieldPath& path) {
- FieldPath::FieldPathInternal* internal = path.internal_;
// If the path is key (i.e. __name__).
- if (internal->IsKeyFieldPath()) {
- jobject result = env->CallStaticObjectMethod(
- field_path::GetClass(),
- field_path::GetMethodId(field_path::kDocumentId));
- CheckAndClearJniExceptions(env);
- return result;
+ if (internal.IsKeyFieldPath()) {
+ return env.Call(kDocumentId);
}
// Prepare call arguments.
- jsize size = static_cast(internal->size());
- jobjectArray args =
- env->NewObjectArray(size, firebase::util::string::GetClass(),
- /*initialElement=*/nullptr);
- for (jsize i = 0; i < size; ++i) {
- jobject segment = env->NewStringUTF((*internal)[i].c_str());
- env->SetObjectArrayElement(args, i, segment);
- env->DeleteLocalRef(segment);
- CheckAndClearJniExceptions(env);
+ size_t size = internal.size();
+ Local> args = env.NewArray(size, String::GetClass());
+ for (size_t i = 0; i < size; ++i) {
+ args.Set(env, i, env.NewStringUtf(internal[i]));
}
- // Make JNI call and check for error.
- jobject result = env->CallStaticObjectMethod(
- field_path::GetClass(), field_path::GetMethodId(field_path::kOf), args);
- CheckAndClearJniExceptions(env);
- env->DeleteLocalRef(args);
-
- return result;
-}
-
-/* static */
-bool FieldPathConverter::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = field_path::CacheMethodIds(env, activity);
- firebase::util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void FieldPathConverter::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- field_path::ReleaseClass(env);
- firebase::util::CheckAndClearJniExceptions(env);
+ return env.Call(kOf, args);
}
} // namespace firestore
diff --git a/firestore/src/android/field_path_android.h b/firestore/src/android/field_path_android.h
index 9cb718f052..fa08f322c3 100644
--- a/firestore/src/android/field_path_android.h
+++ b/firestore/src/android/field_path_android.h
@@ -1,10 +1,8 @@
#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIELD_PATH_ANDROID_H_
#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIELD_PATH_ANDROID_H_
-#include
-
-#include "app/src/include/firebase/app.h"
#include "firestore/src/include/firebase/firestore/field_path.h"
+#include "firestore/src/jni/jni_fwd.h"
namespace firebase {
namespace firestore {
@@ -16,17 +14,13 @@ class FieldPathConverter {
public:
using ApiType = FieldPath;
- // Convert a C++ FieldPath to a Java FieldPath.
- static jobject ToJavaObject(JNIEnv* env, const FieldPath& path);
+ static void Initialize(jni::Loader& loader);
+
+ /** Creates a Java FieldPath from a C++ FieldPath. */
+ static jni::Local Create(jni::Env& env, const FieldPath& path);
// We do not need to convert Java FieldPath back to C++ FieldPath since there
// is no public API that returns a FieldPath yet.
-
- private:
- friend class FirestoreInternal;
-
- static bool Initialize(App* app);
- static void Terminate(App* app);
};
} // namespace firestore
diff --git a/firestore/src/android/field_value_android.cc b/firestore/src/android/field_value_android.cc
index 52ada216c1..218bdd7216 100644
--- a/firestore/src/android/field_value_android.cc
+++ b/firestore/src/android/field_value_android.cc
@@ -9,12 +9,22 @@
#include "firestore/src/android/geo_point_android.h"
#include "firestore/src/android/timestamp_android.h"
#include "firestore/src/android/util_android.h"
+#include "firestore/src/jni/class.h"
+#include "firestore/src/jni/env.h"
namespace firebase {
namespace firestore {
+namespace {
+
+using jni::Array;
+using jni::Env;
+using jni::Local;
+using jni::Object;
using Type = FieldValue::Type;
+} // namespace
+
// com.google.firebase.firestore.FieldValue is the public type which contains
// static methods to build sentinel values.
// clang-format off
@@ -89,10 +99,9 @@ FieldValueInternal::FieldValueInternal(double value)
FieldValueInternal::FieldValueInternal(Timestamp value)
: cached_type_(Type::kTimestamp) {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject obj = TimestampInternal::TimestampToJavaTimestamp(env, value);
- obj_ = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
+ Env env;
+ Local obj = TimestampInternal::Create(env, value);
+ obj_ = env.get()->NewGlobalRef(obj.get());
}
FieldValueInternal::FieldValueInternal(std::string value)
@@ -111,11 +120,9 @@ FieldValueInternal::FieldValueInternal(std::string value)
// blob_value().
FieldValueInternal::FieldValueInternal(const uint8_t* value, size_t size)
: cached_type_(Type::kBlob) {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject obj = BlobInternal::BlobToJavaBlob(env, value, size);
- obj_ = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
- CheckAndClearJniExceptions(env);
+ Env env = GetEnv();
+ Local obj = BlobInternal::Create(env, value, size);
+ obj_ = env.get()->NewGlobalRef(obj.get());
FIREBASE_ASSERT(obj_ != nullptr);
}
@@ -124,10 +131,9 @@ FieldValueInternal::FieldValueInternal(DocumentReference value)
FieldValueInternal::FieldValueInternal(GeoPoint value)
: cached_type_(Type::kGeoPoint) {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jobject obj = GeoPointInternal::GeoPointToJavaGeoPoint(env, value);
- obj_ = env->NewGlobalRef(obj);
- env->DeleteLocalRef(obj);
+ Env env = GetEnv();
+ Local obj = GeoPointInternal::Create(env, value);
+ obj_ = env.get()->NewGlobalRef(obj.get());
}
FieldValueInternal::FieldValueInternal(std::vector value)
@@ -186,7 +192,7 @@ Type FieldValueInternal::type() const {
cached_type_ = Type::kDouble;
return Type::kDouble;
}
- if (env->IsInstanceOf(obj_, TimestampInternal::GetClass())) {
+ if (env->IsInstanceOf(obj_, TimestampInternal::GetClass().get())) {
cached_type_ = Type::kTimestamp;
return Type::kTimestamp;
}
@@ -194,15 +200,15 @@ Type FieldValueInternal::type() const {
cached_type_ = Type::kString;
return Type::kString;
}
- if (env->IsInstanceOf(obj_, BlobInternal::GetClass())) {
+ if (env->IsInstanceOf(obj_, BlobInternal::GetClass().get())) {
cached_type_ = Type::kBlob;
return Type::kBlob;
}
- if (env->IsInstanceOf(obj_, DocumentReferenceInternal::GetClass())) {
+ if (env->IsInstanceOf(obj_, DocumentReferenceInternal::GetClass().get())) {
cached_type_ = Type::kReference;
return Type::kReference;
}
- if (env->IsInstanceOf(obj_, GeoPointInternal::GetClass())) {
+ if (env->IsInstanceOf(obj_, GeoPointInternal::GetClass().get())) {
cached_type_ = Type::kGeoPoint;
return Type::kGeoPoint;
}
@@ -263,17 +269,17 @@ double FieldValueInternal::double_value() const {
}
Timestamp FieldValueInternal::timestamp_value() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
+ Env env;
// Make sure this instance is of correct type.
if (cached_type_ == Type::kNull) {
- FIREBASE_ASSERT(env->IsInstanceOf(obj_, TimestampInternal::GetClass()));
+ FIREBASE_ASSERT(env.IsInstanceOf(obj_, TimestampInternal::GetClass()));
cached_type_ = Type::kTimestamp;
} else {
FIREBASE_ASSERT(cached_type_ == Type::kTimestamp);
}
- return TimestampInternal::JavaTimestampToTimestamp(env, obj_);
+ return TimestampInternal(obj_).ToPublic(env);
}
std::string FieldValueInternal::string_value() const {
@@ -291,55 +297,57 @@ std::string FieldValueInternal::string_value() const {
}
const uint8_t* FieldValueInternal::blob_value() const {
- if (blob_size() == 0) {
- // Doesn't matter what we return. Not return &(cached_blob_.get()->front())
- // to avoid going into undefined-behavior world. Once we drop the support of
- // STLPort, we might just combine this case into the logic below by calling
- // cached_blob_.get()->data().
+ static_assert(sizeof(uint8_t) == sizeof(jbyte),
+ "uint8_t and jbyte must be of same size");
+
+ Env env = GetEnv();
+ EnsureCachedBlob(env);
+ if (!env.ok() || cached_blob_.get() == nullptr) {
return nullptr;
}
- if (cached_blob_.get()) {
- return &(cached_blob_.get()->front());
+ if (cached_blob_->empty()) {
+ // The return value doesn't matter, but we can't return
+ // `&cached_blob->front()` because calling `front` on an empty vector is
+ // undefined behavior. When we drop support for STLPort, we can use `data`
+ // instead which is defined, even for empty vectors.
+ // TODO(b/163140650): remove this special case.
+ return nullptr;
}
- size_t size = blob_size();
- // firebase::SharedPtr does not have set() API.
- cached_blob_ =
- SharedPtr>{new std::vector(size)};
-
- JNIEnv* env = firestore_->app()->GetJNIEnv();
- jbyteArray bytes = BlobInternal::JavaBlobToJbyteArray(env, obj_);
- static_assert(sizeof(uint8_t) == sizeof(jbyte),
- "uint8_t and jbyte must be of same size");
- env->GetByteArrayRegion(
- bytes, 0, size, reinterpret_cast(&(cached_blob_.get()->front())));
- env->DeleteLocalRef(bytes);
-
- CheckAndClearJniExceptions(env);
- return &(cached_blob_.get()->front());
+ return &(cached_blob_->front());
}
size_t FieldValueInternal::blob_size() const {
- if (cached_blob_.get()) {
- return cached_blob_.get()->size();
+ Env env = GetEnv();
+ EnsureCachedBlob(env);
+ if (!env.ok() || cached_blob_.get() == nullptr) {
+ return 0;
}
- JNIEnv* env = firestore_->app()->GetJNIEnv();
+ return cached_blob_->size();
+}
- // Make sure this instance is of correct type.
+void FieldValueInternal::EnsureCachedBlob(Env& env) const {
if (cached_type_ == Type::kNull) {
- FIREBASE_ASSERT(env->IsInstanceOf(obj_, BlobInternal::GetClass()));
+ FIREBASE_ASSERT(env.IsInstanceOf(Object(obj_), BlobInternal::GetClass()));
cached_type_ = Type::kBlob;
} else {
FIREBASE_ASSERT(cached_type_ == Type::kBlob);
}
+ if (cached_blob_.get() != nullptr) {
+ return;
+ }
- jbyteArray bytes = BlobInternal::JavaBlobToJbyteArray(env, obj_);
- jsize result = env->GetArrayLength(bytes);
- env->DeleteLocalRef(bytes);
- CheckAndClearJniExceptions(env);
- return static_cast(result);
+ Local> bytes = BlobInternal(obj_).ToBytes(env);
+ size_t size = bytes.Size(env);
+
+ auto result = MakeShared>(size);
+ env.GetArrayRegion(bytes, 0, size, &(result->front()));
+
+ if (env.ok()) {
+ cached_blob_ = Move(result);
+ }
}
DocumentReference FieldValueInternal::reference_value() const {
@@ -348,7 +356,7 @@ DocumentReference FieldValueInternal::reference_value() const {
// Make sure this instance is of correct type.
if (cached_type_ == Type::kNull) {
FIREBASE_ASSERT(
- env->IsInstanceOf(obj_, DocumentReferenceInternal::GetClass()));
+ env->IsInstanceOf(obj_, DocumentReferenceInternal::GetClass().get()));
cached_type_ = Type::kReference;
} else {
FIREBASE_ASSERT(cached_type_ == Type::kReference);
@@ -362,17 +370,17 @@ DocumentReference FieldValueInternal::reference_value() const {
}
GeoPoint FieldValueInternal::geo_point_value() const {
- JNIEnv* env = firestore_->app()->GetJNIEnv();
+ Env env = GetEnv();
// Make sure this instance is of correct type.
if (cached_type_ == Type::kNull) {
- FIREBASE_ASSERT(env->IsInstanceOf(obj_, GeoPointInternal::GetClass()));
+ FIREBASE_ASSERT(env.IsInstanceOf(obj_, GeoPointInternal::GetClass()));
cached_type_ = Type::kGeoPoint;
} else {
FIREBASE_ASSERT(cached_type_ == Type::kGeoPoint);
}
- return GeoPointInternal::JavaGeoPointToGeoPoint(env, obj_);
+ return GeoPointInternal(obj_).ToPublic(env);
}
std::vector FieldValueInternal::array_value() const {
@@ -605,17 +613,8 @@ void FieldValueInternal::Terminate(App* app) {
}
bool operator==(const FieldValueInternal& lhs, const FieldValueInternal& rhs) {
- // Most likely only happens when comparing one with itself or both are Null.
- if (lhs.obj_ == rhs.obj_) {
- return true;
- }
-
- // If only one of them is Null, then they cannot equal.
- if (lhs.obj_ == nullptr || rhs.obj_ == nullptr) {
- return false;
- }
-
- return lhs.EqualsJavaObject(rhs);
+ Env env = FirestoreInternal::GetEnv();
+ return Object::Equals(env, lhs.ToJava(), rhs.ToJava());
}
jobject FieldValueInternal::TryGetJobject(const FieldValue& value) {
diff --git a/firestore/src/android/field_value_android.h b/firestore/src/android/field_value_android.h
index c307cc5c17..07f18a37c3 100644
--- a/firestore/src/android/field_value_android.h
+++ b/firestore/src/android/field_value_android.h
@@ -9,6 +9,7 @@
#include "firestore/src/android/wrapper.h"
#include "firestore/src/include/firebase/firestore/document_reference.h"
#include "firestore/src/include/firebase/firestore/field_value.h"
+#include "firestore/src/jni/jni_fwd.h"
#include "firebase/firestore/geo_point.h"
#include "firebase/firestore/timestamp.h"
@@ -68,6 +69,8 @@ class FieldValueInternal : public Wrapper {
static bool Initialize(App* app);
static void Terminate(App* app);
+ void EnsureCachedBlob(jni::Env& env) const;
+
static jobject TryGetJobject(const FieldValue& value);
static jobject delete_;
@@ -81,6 +84,14 @@ class FieldValueInternal : public Wrapper {
bool operator==(const FieldValueInternal& lhs, const FieldValueInternal& rhs);
+inline jobject ToJni(const FieldValueInternal* value) {
+ return value->java_object();
+}
+
+inline jobject ToJni(const FieldValueInternal& value) {
+ return value.java_object();
+}
+
} // namespace firestore
} // namespace firebase
diff --git a/firestore/src/android/firebase_firestore_exception_android.cc b/firestore/src/android/firebase_firestore_exception_android.cc
deleted file mode 100644
index 6424999cc0..0000000000
--- a/firestore/src/android/firebase_firestore_exception_android.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-#include "firestore/src/android/firebase_firestore_exception_android.h"
-
-#include
-
-#include "firestore/src/android/util_android.h"
-
-namespace firebase {
-namespace firestore {
-
-// clang-format off
-#define FIRESTORE_EXCEPTION_METHODS(X) \
- X(Constructor, "", \
- "(Ljava/lang/String;" \
- "Lcom/google/firebase/firestore/FirebaseFirestoreException$Code;)V"), \
- X(GetCode, "getCode", \
- "()Lcom/google/firebase/firestore/FirebaseFirestoreException$Code;")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(firestore_exception, FIRESTORE_EXCEPTION_METHODS)
-METHOD_LOOKUP_DEFINITION(
- firestore_exception,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/FirebaseFirestoreException",
- FIRESTORE_EXCEPTION_METHODS)
-
-// clang-format off
-#define FIRESTORE_EXCEPTION_CODE_METHODS(X) \
- X(Value, "value", "()I"), \
- X(FromValue, "fromValue", \
- "(I)Lcom/google/firebase/firestore/FirebaseFirestoreException$Code;", \
- util::kMethodTypeStatic)
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(firestore_exception_code,
- FIRESTORE_EXCEPTION_CODE_METHODS)
-METHOD_LOOKUP_DEFINITION(
- firestore_exception_code,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/FirebaseFirestoreException$Code",
- FIRESTORE_EXCEPTION_CODE_METHODS)
-
-#define ILLEGAL_STATE_EXCEPTION_METHODS(X) X(Constructor, "", "()V")
-
-METHOD_LOOKUP_DECLARATION(illegal_state_exception,
- ILLEGAL_STATE_EXCEPTION_METHODS)
-METHOD_LOOKUP_DEFINITION(illegal_state_exception,
- PROGUARD_KEEP_CLASS "java/lang/IllegalStateException",
- ILLEGAL_STATE_EXCEPTION_METHODS)
-
-/* static */
-Error FirebaseFirestoreExceptionInternal::ToErrorCode(JNIEnv* env,
- jobject exception) {
- if (exception == nullptr) {
- return Error::kErrorOk;
- }
-
- // Some of the Precondition failure is thrown as IllegalStateException instead
- // of a FirebaseFirestoreException. So we convert them into a more meaningful
- // code.
- if (env->IsInstanceOf(exception, illegal_state_exception::GetClass())) {
- return Error::kErrorFailedPrecondition;
- } else if (!IsInstance(env, exception)) {
- return Error::kErrorUnknown;
- }
-
- jobject code = env->CallObjectMethod(
- exception,
- firestore_exception::GetMethodId(firestore_exception::kGetCode));
- jint code_value = env->CallIntMethod(
- code,
- firestore_exception_code::GetMethodId(firestore_exception_code::kValue));
- env->DeleteLocalRef(code);
- CheckAndClearJniExceptions(env);
-
- if (code_value > Error::kErrorUnauthenticated ||
- code_value < Error::kErrorOk) {
- return Error::kErrorUnknown;
- }
- return static_cast(code_value);
-}
-
-/* static */
-std::string FirebaseFirestoreExceptionInternal::ToString(JNIEnv* env,
- jobject exception) {
- return util::GetMessageFromException(env, exception);
-}
-
-/* static */
-jthrowable FirebaseFirestoreExceptionInternal::ToException(
- JNIEnv* env, Error code, const char* message) {
- if (code == Error::kErrorOk) {
- return nullptr;
- }
- // FirebaseFirestoreException requires message to be non-empty. If the caller
- // does not bother to give details, we assign an arbitrary message here.
- if (message == nullptr || strlen(message) == 0) {
- message = "Unknown Exception";
- }
-
- jstring exception_message = env->NewStringUTF(message);
- jobject exception_code =
- env->CallStaticObjectMethod(firestore_exception_code::GetClass(),
- firestore_exception_code::GetMethodId(
- firestore_exception_code::kFromValue),
- static_cast(code));
- jthrowable result = static_cast(env->NewObject(
- firestore_exception::GetClass(),
- firestore_exception::GetMethodId(firestore_exception::kConstructor),
- exception_message, exception_code));
- env->DeleteLocalRef(exception_message);
- env->DeleteLocalRef(exception_code);
- CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-jthrowable FirebaseFirestoreExceptionInternal::ToException(
- JNIEnv* env, jthrowable exception) {
- if (IsInstance(env, exception)) {
- return static_cast(env->NewLocalRef(exception));
- } else {
- return ToException(env, ToErrorCode(env, exception),
- ToString(env, exception).c_str());
- }
-}
-
-/* static */
-bool FirebaseFirestoreExceptionInternal::IsInstance(JNIEnv* env,
- jobject exception) {
- return env->IsInstanceOf(exception, firestore_exception::GetClass());
-}
-
-/* static */
-bool FirebaseFirestoreExceptionInternal::IsFirestoreException(
- JNIEnv* env, jobject exception) {
- return IsInstance(env, exception) ||
- env->IsInstanceOf(exception, illegal_state_exception::GetClass());
-}
-
-/* static */
-bool FirebaseFirestoreExceptionInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = firestore_exception::CacheMethodIds(env, activity) &&
- firestore_exception_code::CacheMethodIds(env, activity) &&
- illegal_state_exception::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void FirebaseFirestoreExceptionInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- firestore_exception::ReleaseClass(env);
- firestore_exception_code::ReleaseClass(env);
- illegal_state_exception::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
-}
-
-} // namespace firestore
-} // namespace firebase
diff --git a/firestore/src/android/firebase_firestore_exception_android.h b/firestore/src/android/firebase_firestore_exception_android.h
deleted file mode 100644
index 04c61307b1..0000000000
--- a/firestore/src/android/firebase_firestore_exception_android.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIREBASE_FIRESTORE_EXCEPTION_ANDROID_H_
-#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIREBASE_FIRESTORE_EXCEPTION_ANDROID_H_
-
-#include
-
-#include "app/src/include/firebase/app.h"
-#include "app/src/util_android.h"
-#include "firebase/firestore/firestore_errors.h"
-
-namespace firebase {
-namespace firestore {
-
-class FirebaseFirestoreExceptionInternal {
- public:
- static Error ToErrorCode(JNIEnv* env, jobject exception);
- static std::string ToString(JNIEnv* env, jobject exception);
- static jthrowable ToException(JNIEnv* env, Error code, const char* message);
- static jthrowable ToException(JNIEnv* env, jthrowable exception);
- static bool IsInstance(JNIEnv* env, jobject exception);
- static bool IsFirestoreException(JNIEnv* env, jobject exception);
-
- private:
- friend class FirestoreInternal;
-
- static bool Initialize(App* app);
- static void Terminate(App* app);
-};
-
-} // namespace firestore
-} // namespace firebase
-
-#endif // FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIREBASE_FIRESTORE_EXCEPTION_ANDROID_H_
diff --git a/firestore/src/android/firebase_firestore_settings_android.cc b/firestore/src/android/firebase_firestore_settings_android.cc
deleted file mode 100644
index 05c1f4a8e7..0000000000
--- a/firestore/src/android/firebase_firestore_settings_android.cc
+++ /dev/null
@@ -1,135 +0,0 @@
-#include "firestore/src/android/firebase_firestore_settings_android.h"
-
-#include "firestore/src/android/util_android.h"
-
-namespace firebase {
-namespace firestore {
-
-// clang-format off
-#define SETTINGS_BUILDER_METHODS(X) \
- X(Constructor, "", "()V", util::kMethodTypeInstance), \
- X(SetHost, "setHost", "(Ljava/lang/String;)" \
- "Lcom/google/firebase/firestore/FirebaseFirestoreSettings$Builder;"), \
- X(SetSslEnabled, "setSslEnabled", "(Z)" \
- "Lcom/google/firebase/firestore/FirebaseFirestoreSettings$Builder;"), \
- X(SetPersistenceEnabled, "setPersistenceEnabled", "(Z)" \
- "Lcom/google/firebase/firestore/FirebaseFirestoreSettings$Builder;"), \
- X(SetTimestampsInSnapshotsEnabled, "setTimestampsInSnapshotsEnabled", "(Z)" \
- "Lcom/google/firebase/firestore/FirebaseFirestoreSettings$Builder;"), \
- X(Build, "build", \
- "()Lcom/google/firebase/firestore/FirebaseFirestoreSettings;")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(settings_builder, SETTINGS_BUILDER_METHODS)
-METHOD_LOOKUP_DEFINITION(
- settings_builder,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/FirebaseFirestoreSettings$Builder",
- SETTINGS_BUILDER_METHODS)
-
-// clang-format off
-#define SETTINGS_METHODS(X) \
- X(GetHost, "getHost", "()Ljava/lang/String;"), \
- X(IsSslEnabled, "isSslEnabled", "()Z"), \
- X(IsPersistenceEnabled, "isPersistenceEnabled", "()Z")
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(settings, SETTINGS_METHODS)
-METHOD_LOOKUP_DEFINITION(
- settings,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/FirebaseFirestoreSettings",
- SETTINGS_METHODS)
-
-/* static */
-jobject FirebaseFirestoreSettingsInternal::SettingToJavaSetting(
- JNIEnv* env, const Settings& settings) {
- jobject builder = env->NewObject(
- settings_builder::GetClass(),
- settings_builder::GetMethodId(settings_builder::kConstructor));
-
- // Always set Timestamps-in-Snapshots enabled to true.
- jobject builder_timestamp = env->CallObjectMethod(
- builder,
- settings_builder::GetMethodId(
- settings_builder::kSetTimestampsInSnapshotsEnabled),
- static_cast(true));
- env->DeleteLocalRef(builder);
- builder = builder_timestamp;
-
- // Set host
- jstring host = env->NewStringUTF(settings.host().c_str());
- jobject builder_host = env->CallObjectMethod(
- builder, settings_builder::GetMethodId(settings_builder::kSetHost), host);
- env->DeleteLocalRef(builder);
- env->DeleteLocalRef(host);
- builder = builder_host;
-
- // Set SSL enabled
- jobject builder_ssl = env->CallObjectMethod(
- builder, settings_builder::GetMethodId(settings_builder::kSetSslEnabled),
- static_cast(settings.is_ssl_enabled()));
- env->DeleteLocalRef(builder);
- builder = builder_ssl;
-
- // Set Persistence enabled
- jobject builder_persistence = env->CallObjectMethod(
- builder,
- settings_builder::GetMethodId(settings_builder::kSetPersistenceEnabled),
- static_cast(settings.is_persistence_enabled()));
- env->DeleteLocalRef(builder);
- builder = builder_persistence;
-
- // Build
- jobject settings_jobj = env->CallObjectMethod(
- builder, settings_builder::GetMethodId(settings_builder::kBuild));
- env->DeleteLocalRef(builder);
- CheckAndClearJniExceptions(env);
- return settings_jobj;
-}
-
-/* static */
-Settings FirebaseFirestoreSettingsInternal::JavaSettingToSetting(JNIEnv* env,
- jobject obj) {
- Settings result;
-
- // Set host
- jstring host = static_cast(
- env->CallObjectMethod(obj, settings::GetMethodId(settings::kGetHost)));
- result.set_host(util::JStringToString(env, host));
- env->DeleteLocalRef(host);
-
- // Set SSL enabled
- jboolean ssl_enabled = env->CallBooleanMethod(
- obj, settings::GetMethodId(settings::kIsSslEnabled));
- result.set_ssl_enabled(ssl_enabled);
-
- // Set Persistence enabled
- jboolean persistence_enabled = env->CallBooleanMethod(
- obj, settings::GetMethodId(settings::kIsPersistenceEnabled));
- result.set_persistence_enabled(persistence_enabled);
-
- CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-bool FirebaseFirestoreSettingsInternal::Initialize(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- jobject activity = app->activity();
- bool result = settings_builder::CacheMethodIds(env, activity) &&
- settings::CacheMethodIds(env, activity);
- util::CheckAndClearJniExceptions(env);
- return result;
-}
-
-/* static */
-void FirebaseFirestoreSettingsInternal::Terminate(App* app) {
- JNIEnv* env = app->GetJNIEnv();
- settings_builder::ReleaseClass(env);
- settings::ReleaseClass(env);
- util::CheckAndClearJniExceptions(env);
-}
-
-} // namespace firestore
-} // namespace firebase
diff --git a/firestore/src/android/firebase_firestore_settings_android.h b/firestore/src/android/firebase_firestore_settings_android.h
deleted file mode 100644
index cb38634333..0000000000
--- a/firestore/src/android/firebase_firestore_settings_android.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIREBASE_FIRESTORE_SETTINGS_ANDROID_H_
-#define FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIREBASE_FIRESTORE_SETTINGS_ANDROID_H_
-
-#include
-
-#include "app/src/include/firebase/app.h"
-#include "app/src/util_android.h"
-#include "firestore/src/include/firebase/firestore/settings.h"
-
-namespace firebase {
-namespace firestore {
-
-class FirebaseFirestoreSettingsInternal {
- public:
- using ApiType = Settings;
-
- static jobject SettingToJavaSetting(JNIEnv* env, const Settings& settings);
-
- static Settings JavaSettingToSetting(JNIEnv* env, jobject obj);
-
- private:
- friend class FirestoreInternal;
-
- static bool Initialize(App* app);
- static void Terminate(App* app);
-};
-
-} // namespace firestore
-} // namespace firebase
-
-#endif // FIREBASE_FIRESTORE_CLIENT_CPP_SRC_ANDROID_FIREBASE_FIRESTORE_SETTINGS_ANDROID_H_
diff --git a/firestore/src/android/firestore_android.cc b/firestore/src/android/firestore_android.cc
index b61e43c6c7..2adb8fc4d5 100644
--- a/firestore/src/android/firestore_android.cc
+++ b/firestore/src/android/firestore_android.cc
@@ -17,19 +17,20 @@
#include "firestore/src/android/document_reference_android.h"
#include "firestore/src/android/document_snapshot_android.h"
#include "firestore/src/android/event_listener_android.h"
+#include "firestore/src/android/exception_android.h"
#include "firestore/src/android/field_path_android.h"
#include "firestore/src/android/field_value_android.h"
-#include "firestore/src/android/firebase_firestore_exception_android.h"
-#include "firestore/src/android/firebase_firestore_settings_android.h"
#include "firestore/src/android/geo_point_android.h"
#include "firestore/src/android/lambda_event_listener.h"
#include "firestore/src/android/lambda_transaction_function.h"
+#include "firestore/src/android/listener_registration_android.h"
#include "firestore/src/android/metadata_changes_android.h"
#include "firestore/src/android/promise_android.h"
#include "firestore/src/android/query_android.h"
#include "firestore/src/android/query_snapshot_android.h"
#include "firestore/src/android/server_timestamp_behavior_android.h"
#include "firestore/src/android/set_options_android.h"
+#include "firestore/src/android/settings_android.h"
#include "firestore/src/android/snapshot_metadata_android.h"
#include "firestore/src/android/source_android.h"
#include "firestore/src/android/timestamp_android.h"
@@ -38,89 +39,117 @@
#include "firestore/src/android/wrapper.h"
#include "firestore/src/android/write_batch_android.h"
#include "firestore/src/include/firebase/firestore.h"
+#include "firestore/src/jni/array_list.h"
+#include "firestore/src/jni/boolean.h"
+#include "firestore/src/jni/collection.h"
+#include "firestore/src/jni/double.h"
+#include "firestore/src/jni/env.h"
+#include "firestore/src/jni/hash_map.h"
+#include "firestore/src/jni/integer.h"
+#include "firestore/src/jni/iterator.h"
#include "firestore/src/jni/jni.h"
+#include "firestore/src/jni/list.h"
+#include "firestore/src/jni/loader.h"
+#include "firestore/src/jni/long.h"
+#include "firestore/src/jni/map.h"
+#include "firestore/src/jni/set.h"
namespace firebase {
namespace firestore {
+namespace {
+
+using jni::Constructor;
+using jni::Env;
+using jni::Loader;
+using jni::Local;
+using jni::Method;
+using jni::Object;
+using jni::StaticMethod;
+using jni::String;
+
+constexpr char kFirestoreClassName[] =
+ PROGUARD_KEEP_CLASS "com/google/firebase/firestore/FirebaseFirestore";
+
+Method kCollection(
+ "collection",
+ "(Ljava/lang/String;)"
+ "Lcom/google/firebase/firestore/CollectionReference;");
+Method kDocument("document",
+ "(Ljava/lang/String;)"
+ "Lcom/google/firebase/firestore/DocumentReference;");
+Method kCollectionGroup("collectionGroup",
+ "(Ljava/lang/String;)"
+ "Lcom/google/firebase/firestore/Query;");
+Method kGetSettings(
+ "getFirestoreSettings",
+ "()Lcom/google/firebase/firestore/FirebaseFirestoreSettings;");
+StaticMethod kGetInstance(
+ "getInstance",
+ "(Lcom/google/firebase/FirebaseApp;)"
+ "Lcom/google/firebase/firestore/FirebaseFirestore;");
+StaticMethod kSetLoggingEnabled("setLoggingEnabled", "(Z)V");
+StaticMethod kSetClientLanguage("setClientLanguage",
+ "(Ljava/lang/String;)V");
+Method kSetSettings(
+ "setFirestoreSettings",
+ "(Lcom/google/firebase/firestore/FirebaseFirestoreSettings;)V");
+Method kBatch("batch", "()Lcom/google/firebase/firestore/WriteBatch;");
+Method kRunTransaction(
+ "runTransaction",
+ "(Lcom/google/firebase/firestore/Transaction$Function;)"
+ "Lcom/google/android/gms/tasks/Task;");
+Method kEnableNetwork("enableNetwork",
+ "()Lcom/google/android/gms/tasks/Task;");
+Method kDisableNetwork("disableNetwork",
+ "()Lcom/google/android/gms/tasks/Task;");
+Method kTerminate("terminate", "()Lcom/google/android/gms/tasks/Task;");
+Method kWaitForPendingWrites("waitForPendingWrites",
+ "()Lcom/google/android/gms/tasks/Task;");
+Method kClearPersistence("clearPersistence",
+ "()Lcom/google/android/gms/tasks/Task;");
+Method kAddSnapshotsInSyncListener(
+ "addSnapshotsInSyncListener",
+ "(Ljava/util/concurrent/Executor;Ljava/lang/Runnable;)"
+ "Lcom/google/firebase/firestore/ListenerRegistration;");
+
+void InitializeFirestore(Loader& loader) {
+ loader.LoadClass(kFirestoreClassName, kCollection, kDocument,
+ kCollectionGroup, kGetSettings, kGetInstance,
+ kSetLoggingEnabled, kSetClientLanguage, kSetSettings, kBatch,
+ kRunTransaction, kEnableNetwork, kDisableNetwork, kTerminate,
+ kWaitForPendingWrites, kClearPersistence,
+ kAddSnapshotsInSyncListener);
+}
-const char kApiIdentifier[] = "Firestore";
+constexpr char kUserCallbackExecutorClassName[] = PROGUARD_KEEP_CLASS
+ "com/google/firebase/firestore/internal/cpp/"
+ "SilentRejectionSingleThreadExecutor";
+Constructor kNewUserCallbackExecutor("()V");
+Method kExecutorShutdown("shutdown", "()V");
+
+void InitializeUserCallbackExecutor(Loader& loader) {
+ loader.LoadClass(kUserCallbackExecutorClassName, kNewUserCallbackExecutor,
+ kExecutorShutdown);
+}
+
+} // namespace
-// clang-format off
-#define FIREBASE_FIRESTORE_METHODS(X) \
- X(Collection, "collection", \
- "(Ljava/lang/String;)" \
- "Lcom/google/firebase/firestore/CollectionReference;"), \
- X(Document, "document", \
- "(Ljava/lang/String;)" \
- "Lcom/google/firebase/firestore/DocumentReference;"), \
- X(CollectionGroup, "collectionGroup", \
- "(Ljava/lang/String;)" \
- "Lcom/google/firebase/firestore/Query;"), \
- X(GetSettings, "getFirestoreSettings", \
- "()Lcom/google/firebase/firestore/FirebaseFirestoreSettings;"), \
- X(GetInstance, "getInstance", \
- "(Lcom/google/firebase/FirebaseApp;)" \
- "Lcom/google/firebase/firestore/FirebaseFirestore;", \
- util::kMethodTypeStatic), \
- X(SetLoggingEnabled, "setLoggingEnabled", \
- "(Z)V", util::kMethodTypeStatic), \
- X(SetSettings, "setFirestoreSettings", \
- "(Lcom/google/firebase/firestore/FirebaseFirestoreSettings;)V"), \
- X(Batch, "batch", \
- "()Lcom/google/firebase/firestore/WriteBatch;"), \
- X(RunTransaction, "runTransaction", \
- "(Lcom/google/firebase/firestore/Transaction$Function;)" \
- "Lcom/google/android/gms/tasks/Task;"), \
- X(EnableNetwork, "enableNetwork", \
- "()Lcom/google/android/gms/tasks/Task;"), \
- X(DisableNetwork, "disableNetwork", \
- "()Lcom/google/android/gms/tasks/Task;"), \
- X(Terminate, "terminate", \
- "()Lcom/google/android/gms/tasks/Task;"), \
- X(WaitForPendingWrites, "waitForPendingWrites", \
- "()Lcom/google/android/gms/tasks/Task;"), \
- X(ClearPersistence, "clearPersistence", \
- "()Lcom/google/android/gms/tasks/Task;"), \
- X(AddSnapshotsInSyncListener, "addSnapshotsInSyncListener", \
- "(Ljava/util/concurrent/Executor;Ljava/lang/Runnable;)" \
- "Lcom/google/firebase/firestore/ListenerRegistration;")
-
-// clang-format on
-
-METHOD_LOOKUP_DECLARATION(firebase_firestore, FIREBASE_FIRESTORE_METHODS)
-METHOD_LOOKUP_DEFINITION(firebase_firestore,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/FirebaseFirestore",
- FIREBASE_FIRESTORE_METHODS)
-
-#define SILENT_REJECTION_EXECUTOR_METHODS(X) X(Constructor, "", "()V")
-METHOD_LOOKUP_DECLARATION(silent_rejection_executor,
- SILENT_REJECTION_EXECUTOR_METHODS)
-METHOD_LOOKUP_DEFINITION(silent_rejection_executor,
- PROGUARD_KEEP_CLASS
- "com/google/firebase/firestore/internal/cpp/"
- "SilentRejectionSingleThreadExecutor",
- SILENT_REJECTION_EXECUTOR_METHODS)
+const char kApiIdentifier[] = "Firestore";
Mutex FirestoreInternal::init_mutex_; // NOLINT
int FirestoreInternal::initialize_count_ = 0;
+Loader* FirestoreInternal::loader_ = nullptr;
FirestoreInternal::FirestoreInternal(App* app) {
FIREBASE_ASSERT(app != nullptr);
if (!Initialize(app)) return;
app_ = app;
- JNIEnv* env = app_->GetJNIEnv();
- jobject platform_app = app_->GetPlatformApp();
- jobject firestore_obj = env->CallStaticObjectMethod(
- firebase_firestore::GetClass(),
- firebase_firestore::GetMethodId(firebase_firestore::kGetInstance),
- platform_app);
- util::CheckAndClearJniExceptions(env);
- env->DeleteLocalRef(platform_app);
- FIREBASE_ASSERT(firestore_obj != nullptr);
- obj_ = env->NewGlobalRef(firestore_obj);
- env->DeleteLocalRef(firestore_obj);
+ Env env = GetEnv();
+ Local platform_app(env.get(), app_->GetPlatformApp());
+ Local java_firestore = env.Call(kGetInstance, platform_app);
+ FIREBASE_ASSERT(java_firestore.get() != nullptr);
+ obj_ = java_firestore;
// Mainly for enabling TimestampsInSnapshotsEnabled. The rest comes from the
// default in native SDK. The C++ implementation relies on that for reading
@@ -128,17 +157,12 @@ FirestoreInternal::FirestoreInternal(App* app) {
// default, we may safely remove the calls below.
set_settings(settings());
- jobject user_callback_executor_obj =
- env->NewObject(silent_rejection_executor::GetClass(),
- silent_rejection_executor::GetMethodId(
- silent_rejection_executor::kConstructor));
+ Local java_user_callback_executor = env.New(kNewUserCallbackExecutor);
- CheckAndClearJniExceptions(env);
- FIREBASE_ASSERT(user_callback_executor_obj != nullptr);
- user_callback_executor_ = env->NewGlobalRef(user_callback_executor_obj);
- env->DeleteLocalRef(user_callback_executor_obj);
+ FIREBASE_ASSERT(java_user_callback_executor.get() != nullptr);
+ user_callback_executor_ = java_user_callback_executor;
- future_manager_.AllocFutureApi(this, static_cast(FirestoreFn::kCount));
+ future_manager_.AllocFutureApi(this, static_cast