Repository: firebase/quickstart-android Branch: master Commit: 7da89ea2e750 Files: 658 Total size: 1.5 MB Directory structure: gitextract_q82ekbdt/ ├── .editorconfig ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── config.yml │ │ └── quickstart_issue.md │ └── workflows/ │ └── android.yml ├── .gitignore ├── .google/ │ └── packaging.yaml ├── .opensource/ │ └── project.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── admob/ │ ├── .gitignore │ ├── .google/ │ │ └── packaging.yaml │ ├── README.md │ ├── app/ │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── samples/ │ │ │ └── quickstart/ │ │ │ └── admobexample/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ ├── FirstFragment.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── SecondFragment.java │ │ │ └── kotlin/ │ │ │ ├── FirstFragment.kt │ │ │ ├── MainActivity.kt │ │ │ └── SecondFragment.kt │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── fragment_first.xml │ │ │ └── fragment_second.xml │ │ ├── navigation/ │ │ │ ├── nav_graph_java.xml │ │ │ └── nav_graph_kotlin.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── analytics/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── analytics/ │ │ │ └── MainActivityTest.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── analytics/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ ├── ImageFragment.java │ │ │ │ ├── ImageInfo.java │ │ │ │ └── MainActivity.java │ │ │ └── kotlin/ │ │ │ ├── ImageFragment.kt │ │ │ ├── ImageInfo.kt │ │ │ └── MainActivity.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ └── circle.xml │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ └── fragment_main.xml │ │ ├── menu/ │ │ │ └── main.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v21/ │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── appdistribution/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── appdistributionquickstart/ │ │ │ └── InstrumentedTest.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── appdistributionquickstart/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ └── MainActivity.java │ │ │ └── kotlin/ │ │ │ └── KotlinMainActivity.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── auth/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── auth/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ ├── AnonymousAuthFragment.java │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── ChooserFragment.java │ │ │ │ ├── CustomAuthFragment.java │ │ │ │ ├── EmailPasswordFragment.java │ │ │ │ ├── FacebookLoginFragment.java │ │ │ │ ├── FirebaseUIFragment.java │ │ │ │ ├── GenericIdpFragment.java │ │ │ │ ├── GoogleSignInFragment.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MultiFactorEnrollFragment.java │ │ │ │ ├── MultiFactorFragment.java │ │ │ │ ├── MultiFactorSignInFragment.java │ │ │ │ ├── MultiFactorUnenrollFragment.java │ │ │ │ ├── PasswordlessActivity.java │ │ │ │ ├── PhoneAuthFragment.java │ │ │ │ └── TokenBroadcastReceiver.java │ │ │ └── kotlin/ │ │ │ ├── AnonymousAuthFragment.kt │ │ │ ├── BaseActivity.kt │ │ │ ├── BaseFragment.kt │ │ │ ├── ChooserFragment.kt │ │ │ ├── CustomAuthFragment.kt │ │ │ ├── EmailPasswordFragment.kt │ │ │ ├── FacebookLoginFragment.kt │ │ │ ├── FirebaseUIFragment.kt │ │ │ ├── GenericIdpFragment.kt │ │ │ ├── GoogleSignInFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MultiFactorEnrollFragment.kt │ │ │ ├── MultiFactorFragment.kt │ │ │ ├── MultiFactorSignInFragment.kt │ │ │ ├── MultiFactorUnenrollFragment.kt │ │ │ ├── PasswordlessActivity.kt │ │ │ ├── PhoneAuthFragment.kt │ │ │ └── TokenBroadcastReceiver.kt │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── activity_passwordless.xml │ │ │ ├── fragment_anonymous_auth.xml │ │ │ ├── fragment_chooser.xml │ │ │ ├── fragment_custom.xml │ │ │ ├── fragment_emailpassword.xml │ │ │ ├── fragment_facebook.xml │ │ │ ├── fragment_firebase_ui.xml │ │ │ ├── fragment_generic_idp.xml │ │ │ ├── fragment_google.xml │ │ │ ├── fragment_multi_factor.xml │ │ │ ├── fragment_multi_factor_sign_in.xml │ │ │ ├── fragment_passwordless.xml │ │ │ ├── fragment_phone_auth.xml │ │ │ └── item_spinner_list.xml │ │ ├── navigation/ │ │ │ ├── nav_graph_java.xml │ │ │ └── nav_graph_kotlin.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── ids.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-land/ │ │ │ └── dimens.xml │ │ ├── values-v21/ │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle.kts │ └── web/ │ └── auth.html ├── build.gradle.kts ├── build_pull_request.sh ├── config/ │ ├── README.md │ ├── app/ │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── samples/ │ │ │ └── quickstart/ │ │ │ └── config/ │ │ │ └── MainActivityTest.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── samples/ │ │ │ └── quickstart/ │ │ │ └── config/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ └── MainActivity.java │ │ │ └── kotlin/ │ │ │ └── MainActivity.kt │ │ └── res/ │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-w820dp/ │ │ │ └── dimens.xml │ │ └── xml/ │ │ └── remote_config_defaults.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── copy_mock_google_services_json.sh ├── crash/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ ├── src/ │ │ │ ├── androidTest/ │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── google/ │ │ │ │ └── samples/ │ │ │ │ └── quickstart/ │ │ │ │ └── crash/ │ │ │ │ └── MainActivityTest.java │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── google/ │ │ │ │ └── samples/ │ │ │ │ └── quickstart/ │ │ │ │ └── crash/ │ │ │ │ ├── EntryChoiceActivity.kt │ │ │ │ ├── java/ │ │ │ │ │ ├── CustomKeySamples.java │ │ │ │ │ └── MainActivity.java │ │ │ │ └── kotlin/ │ │ │ │ ├── CustomKeySamples.kt │ │ │ │ └── MainActivity.kt │ │ │ └── res/ │ │ │ ├── layout/ │ │ │ │ └── activity_main.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── values-w820dp/ │ │ │ └── dimens.xml │ │ └── test-proguard-rules.pro │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── database/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── database/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MainFragment.java │ │ │ │ ├── NewPostFragment.java │ │ │ │ ├── PostDetailFragment.java │ │ │ │ ├── SignInFragment.java │ │ │ │ ├── listfragments/ │ │ │ │ │ ├── MyPostsFragment.java │ │ │ │ │ ├── MyTopPostsFragment.java │ │ │ │ │ ├── PostListFragment.java │ │ │ │ │ └── RecentPostsFragment.java │ │ │ │ ├── models/ │ │ │ │ │ ├── Comment.java │ │ │ │ │ ├── Post.java │ │ │ │ │ └── User.java │ │ │ │ └── viewholder/ │ │ │ │ ├── CommentViewHolder.java │ │ │ │ └── PostViewHolder.java │ │ │ └── kotlin/ │ │ │ ├── BaseFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MainFragment.kt │ │ │ ├── NewPostFragment.kt │ │ │ ├── PostDetailFragment.kt │ │ │ ├── SignInFragment.kt │ │ │ ├── listfragments/ │ │ │ │ ├── MyPostsFragment.kt │ │ │ │ ├── MyTopPostsFragment.kt │ │ │ │ ├── PostListFragment.kt │ │ │ │ └── RecentPostsFragment.kt │ │ │ ├── models/ │ │ │ │ ├── Comment.kt │ │ │ │ ├── Post.kt │ │ │ │ └── User.kt │ │ │ └── viewholder/ │ │ │ ├── CommentViewHolder.kt │ │ │ └── PostViewHolder.kt │ │ └── res/ │ │ ├── layout/ │ │ │ ├── activity_main.xml │ │ │ ├── fragment_all_posts.xml │ │ │ ├── fragment_main.xml │ │ │ ├── fragment_new_post.xml │ │ │ ├── fragment_post_detail.xml │ │ │ ├── fragment_sign_in.xml │ │ │ ├── include_post_author.xml │ │ │ ├── include_post_text.xml │ │ │ ├── item_comment.xml │ │ │ └── item_post.xml │ │ ├── menu/ │ │ │ └── menu_main.xml │ │ ├── navigation/ │ │ │ ├── nav_graph_java.xml │ │ │ └── nav_graph_kotlin.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v21/ │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── dataconnect/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── example/ │ │ │ └── dataconnect/ │ │ │ ├── MainActivity.kt │ │ │ ├── feature/ │ │ │ │ ├── actordetail/ │ │ │ │ │ ├── ActorDetailScreen.kt │ │ │ │ │ ├── ActorDetailUIState.kt │ │ │ │ │ └── ActorDetailViewModel.kt │ │ │ │ ├── moviedetail/ │ │ │ │ │ ├── MovieDetailScreen.kt │ │ │ │ │ ├── MovieDetailUIState.kt │ │ │ │ │ ├── MovieDetailViewModel.kt │ │ │ │ │ └── UserReviews.kt │ │ │ │ ├── movies/ │ │ │ │ │ ├── MoviesScreen.kt │ │ │ │ │ ├── MoviesUIState.kt │ │ │ │ │ └── MoviesViewModel.kt │ │ │ │ ├── profile/ │ │ │ │ │ ├── AuthScreen.kt │ │ │ │ │ ├── ProfileScreen.kt │ │ │ │ │ ├── ProfileUIState.kt │ │ │ │ │ └── ProfileViewModel.kt │ │ │ │ └── search/ │ │ │ │ └── Navigation.kt │ │ │ └── ui/ │ │ │ ├── components/ │ │ │ │ ├── ActorsList.kt │ │ │ │ ├── ErrorCard.kt │ │ │ │ ├── LoadingScreen.kt │ │ │ │ ├── MoviesList.kt │ │ │ │ ├── ReviewCard.kt │ │ │ │ └── ToggleButton.kt │ │ │ └── theme/ │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── firebase_data_connect.xml │ │ │ └── ic_launcher_background.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ └── xml/ │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ ├── build.gradle.kts │ ├── dataconnect/ │ │ ├── dataconnect.yaml │ │ ├── movie-connector/ │ │ │ ├── connector.yaml │ │ │ ├── mutations.gql │ │ │ └── queries.gql │ │ ├── moviedata_insert.gql │ │ └── schema/ │ │ └── schema.gql │ ├── firebase.json │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── dynamiclinks/ │ └── README.md ├── firebase-ai/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── ai/ │ │ │ ├── MainActivity.kt │ │ │ ├── feature/ │ │ │ │ ├── live/ │ │ │ │ │ ├── BidiViewModel.kt │ │ │ │ │ ├── StreamAudioViewModel.kt │ │ │ │ │ └── StreamVideoViewModel.kt │ │ │ │ ├── media/ │ │ │ │ │ └── imagen/ │ │ │ │ │ ├── ImagenGenerationViewModel.kt │ │ │ │ │ ├── ImagenInpaintingViewModel.kt │ │ │ │ │ ├── ImagenOutpaintingViewModel.kt │ │ │ │ │ ├── ImagenStyleTransferViewModel.kt │ │ │ │ │ ├── ImagenSubjectReferenceViewModel.kt │ │ │ │ │ ├── ImagenTemplateViewModel.kt │ │ │ │ │ └── ImagenViewModel.kt │ │ │ │ └── text/ │ │ │ │ ├── AudioSummarizationViewModel.kt │ │ │ │ ├── AudioTranslationViewModel.kt │ │ │ │ ├── ChatViewModel.kt │ │ │ │ ├── CourseRecommendationsViewModel.kt │ │ │ │ ├── DocumentComparisonViewModel.kt │ │ │ │ ├── GoogleSearchGroundingViewModel.kt │ │ │ │ ├── ImageBlogCreatorViewModel.kt │ │ │ │ ├── ImageGenerationViewModel.kt │ │ │ │ ├── ServerPromptTemplateViewModel.kt │ │ │ │ ├── SvgViewModel.kt │ │ │ │ ├── ThinkingChatViewModel.kt │ │ │ │ ├── TranslationViewModel.kt │ │ │ │ ├── TravelTipsViewModel.kt │ │ │ │ ├── VideoHashtagGeneratorViewModel.kt │ │ │ │ ├── VideoSummarizationViewModel.kt │ │ │ │ ├── WeatherChatViewModel.kt │ │ │ │ └── functioncalling/ │ │ │ │ └── WeatherRepository.kt │ │ │ └── ui/ │ │ │ ├── CameraView.kt │ │ │ ├── ChatScreen.kt │ │ │ ├── ChatUiState.kt │ │ │ ├── ImagenScreen.kt │ │ │ ├── ImagenUiState.kt │ │ │ ├── ServerPromptScreen.kt │ │ │ ├── ServerPromptUiState.kt │ │ │ ├── StreamRealtimeScreen.kt │ │ │ ├── StreamRealtimeVideoScreen.kt │ │ │ ├── SvgScreen.kt │ │ │ ├── SvgUiState.kt │ │ │ ├── navigation/ │ │ │ │ ├── FirebaseAISamples.kt │ │ │ │ ├── MainMenuScreen.kt │ │ │ │ └── Sample.kt │ │ │ └── theme/ │ │ │ ├── Color.kt │ │ │ ├── Theme.kt │ │ │ └── Type.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ ├── ic_launcher_background.xml │ │ │ └── round_arrow_drop_down_24.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── mipmap-anydpi-v26/ │ │ │ ├── ic_launcher.xml │ │ │ └── ic_launcher_round.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── strings.xml │ │ │ └── themes.xml │ │ └── xml/ │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── firestore/ │ ├── .gitignore │ ├── CONTRIBUTING.md │ ├── LICENSE │ ├── README.md │ ├── accounts.json │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ ├── src/ │ │ │ ├── androidTest/ │ │ │ │ └── AndroidManifest.xml │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── google/ │ │ │ │ └── firebase/ │ │ │ │ └── example/ │ │ │ │ └── fireeats/ │ │ │ │ ├── EntryChoiceActivity.kt │ │ │ │ ├── java/ │ │ │ │ │ ├── FilterDialogFragment.java │ │ │ │ │ ├── Filters.java │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ ├── MainFragment.java │ │ │ │ │ ├── RatingDialogFragment.java │ │ │ │ │ ├── RestaurantDetailFragment.java │ │ │ │ │ ├── adapter/ │ │ │ │ │ │ ├── FirestoreAdapter.java │ │ │ │ │ │ ├── RatingAdapter.java │ │ │ │ │ │ └── RestaurantAdapter.java │ │ │ │ │ ├── model/ │ │ │ │ │ │ ├── Rating.java │ │ │ │ │ │ └── Restaurant.java │ │ │ │ │ ├── util/ │ │ │ │ │ │ ├── RatingUtil.java │ │ │ │ │ │ └── RestaurantUtil.java │ │ │ │ │ └── viewmodel/ │ │ │ │ │ └── MainActivityViewModel.java │ │ │ │ └── kotlin/ │ │ │ │ ├── FilterDialogFragment.kt │ │ │ │ ├── Filters.kt │ │ │ │ ├── MainActivity.kt │ │ │ │ ├── MainFragment.kt │ │ │ │ ├── RatingDialogFragment.kt │ │ │ │ ├── RestaurantDetailFragment.kt │ │ │ │ ├── adapter/ │ │ │ │ │ ├── FirestoreAdapter.kt │ │ │ │ │ ├── RatingAdapter.kt │ │ │ │ │ └── RestaurantAdapter.kt │ │ │ │ ├── model/ │ │ │ │ │ ├── Rating.kt │ │ │ │ │ └── Restaurant.kt │ │ │ │ ├── util/ │ │ │ │ │ ├── RatingUtil.kt │ │ │ │ │ └── RestaurantUtil.kt │ │ │ │ └── viewmodel/ │ │ │ │ └── MainActivityViewModel.kt │ │ │ └── res/ │ │ │ ├── anim/ │ │ │ │ ├── slide_in_from_left.xml │ │ │ │ ├── slide_in_from_right.xml │ │ │ │ ├── slide_out_to_left.xml │ │ │ │ └── slide_out_to_right.xml │ │ │ ├── drawable/ │ │ │ │ ├── bg_shadow.xml │ │ │ │ ├── gradient_up.xml │ │ │ │ ├── ic_add_white_24px.xml │ │ │ │ ├── ic_arrow_back_white_24px.xml │ │ │ │ ├── ic_close_white_24px.xml │ │ │ │ ├── ic_fastfood_white_24dp.xml │ │ │ │ ├── ic_filter_list_white_24px.xml │ │ │ │ ├── ic_local_dining_white_24px.xml │ │ │ │ ├── ic_monetization_on_white_24px.xml │ │ │ │ ├── ic_place_white_24px.xml │ │ │ │ ├── ic_restaurant_white_24px.xml │ │ │ │ └── ic_sort_white_24px.xml │ │ │ ├── layout/ │ │ │ │ ├── activity_main.xml │ │ │ │ ├── dialog_filters.xml │ │ │ │ ├── dialog_rating.xml │ │ │ │ ├── fragment_main.xml │ │ │ │ ├── fragment_restaurant_detail.xml │ │ │ │ ├── item_rating.xml │ │ │ │ └── item_restaurant.xml │ │ │ ├── menu/ │ │ │ │ └── menu_main.xml │ │ │ ├── navigation/ │ │ │ │ ├── nav_graph_java.xml │ │ │ │ └── nav_graph_kotlin.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ └── values-v21/ │ │ │ └── styles.xml │ │ └── test-proguard-rules.pro │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── indexes.json │ ├── settings.gradle.kts │ └── test_setup.sh ├── functions/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ ├── src/ │ │ │ ├── androidTest/ │ │ │ │ ├── AndroidManifest.xml │ │ │ │ └── java/ │ │ │ │ └── com/ │ │ │ │ └── google/ │ │ │ │ └── samples/ │ │ │ │ └── quickstart/ │ │ │ │ └── functions/ │ │ │ │ ├── MainActivityTest.java │ │ │ │ └── TestAddNumber.java │ │ │ └── main/ │ │ │ ├── AndroidManifest.xml │ │ │ ├── java/ │ │ │ │ └── com/ │ │ │ │ └── google/ │ │ │ │ └── samples/ │ │ │ │ └── quickstart/ │ │ │ │ └── functions/ │ │ │ │ ├── EntryChoiceActivity.kt │ │ │ │ ├── java/ │ │ │ │ │ ├── FunctionsMessagingService.java │ │ │ │ │ └── MainActivity.java │ │ │ │ └── kotlin/ │ │ │ │ ├── FunctionsMessagingService.kt │ │ │ │ └── MainActivity.kt │ │ │ └── res/ │ │ │ ├── layout/ │ │ │ │ └── activity_main.xml │ │ │ ├── values/ │ │ │ │ ├── colors.xml │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── values-w820dp/ │ │ │ │ └── dimens.xml │ │ │ └── xml/ │ │ │ └── network_security_config.xml │ │ └── test-proguard-rules.pro │ ├── build.gradle.kts │ ├── firebase.json │ ├── functions/ │ │ ├── .gitignore │ │ ├── index.js │ │ ├── package.json │ │ └── sanitizer.js │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ ├── settings.gradle.kts │ └── test_setup.sh ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── inappmessaging/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── fiamquickstart/ │ │ │ └── InstrumentedTest.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── fiamquickstart/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ └── MainActivity.java │ │ │ └── kotlin/ │ │ │ └── KotlinMainActivity.kt │ │ └── res/ │ │ ├── drawable/ │ │ │ └── ic_launcher_background.xml │ │ ├── drawable-v24/ │ │ │ └── ic_launcher_foreground.xml │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── internal/ │ ├── chooserx/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── firebase/ │ │ │ └── example/ │ │ │ └── internal/ │ │ │ ├── BaseEntryChoiceActivity.java │ │ │ ├── Choice.java │ │ │ └── ChoiceAdapter.java │ │ └── res/ │ │ └── layout/ │ │ ├── activity_entry_choice.xml │ │ └── item_choice.xml │ ├── lint/ │ │ ├── .gitignore │ │ ├── bin/ │ │ │ ├── main/ │ │ │ │ └── com/ │ │ │ │ └── firebase/ │ │ │ │ └── lint/ │ │ │ │ ├── HungarianNotationDetector.kt │ │ │ │ ├── InvalidImportDetector.kt │ │ │ │ └── QuickstartIssueRegistry.kt │ │ │ └── test/ │ │ │ └── com/ │ │ │ └── firebase/ │ │ │ └── lint/ │ │ │ └── InvalidImportDetectorTest.kt │ │ ├── build.gradle.kts │ │ └── src/ │ │ ├── main/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── firebase/ │ │ │ └── lint/ │ │ │ ├── HungarianNotationDetector.kt │ │ │ ├── InvalidImportDetector.kt │ │ │ └── QuickstartIssueRegistry.kt │ │ └── test/ │ │ └── java/ │ │ └── com/ │ │ └── firebase/ │ │ └── lint/ │ │ └── InvalidImportDetectorTest.kt │ └── lintchecks/ │ ├── .gitignore │ ├── build.gradle.kts │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ └── AndroidManifest.xml ├── messaging/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── fcm/ │ │ │ └── MainActivityEspressoTest.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── fcm/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MyFirebaseMessagingService.java │ │ │ │ └── MyWorker.java │ │ │ └── kotlin/ │ │ │ ├── MainActivity.kt │ │ │ ├── MyFirebaseMessagingService.kt │ │ │ └── MyWorker.kt │ │ └── res/ │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ └── values-w820dp/ │ │ └── dimens.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── mock-google-services.json ├── perf/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── default_content.txt │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── perfmon/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ └── MainActivity.java │ │ │ └── kotlin/ │ │ │ └── MainActivity.kt │ │ └── res/ │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ └── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts ├── scripts/ │ └── checksnippets.py ├── settings.gradle.kts ├── storage/ │ ├── .gitignore │ ├── README.md │ ├── app/ │ │ ├── .gitignore │ │ ├── build.gradle.kts │ │ ├── proguard-rules.pro │ │ └── src/ │ │ ├── androidTest/ │ │ │ └── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── firebasestorage/ │ │ │ ├── MainActivityTest.java │ │ │ └── ServiceIdlingResource.java │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── java/ │ │ │ └── com/ │ │ │ └── google/ │ │ │ └── firebase/ │ │ │ └── quickstart/ │ │ │ └── firebasestorage/ │ │ │ ├── EntryChoiceActivity.kt │ │ │ ├── java/ │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MyBaseTaskService.java │ │ │ │ ├── MyDownloadService.java │ │ │ │ └── MyUploadService.java │ │ │ └── kotlin/ │ │ │ ├── MainActivity.kt │ │ │ ├── MyBaseTaskService.kt │ │ │ ├── MyDownloadService.kt │ │ │ └── MyUploadService.kt │ │ └── res/ │ │ ├── layout/ │ │ │ └── activity_main.xml │ │ ├── menu/ │ │ │ └── menu_main.xml │ │ ├── values/ │ │ │ ├── colors.xml │ │ │ ├── dimens.xml │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-w820dp/ │ │ │ └── dimens.xml │ │ └── xml/ │ │ └── file_paths.xml │ ├── build.gradle.kts │ ├── gradle/ │ │ └── wrapper/ │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ ├── gradle.properties │ ├── gradlew │ ├── gradlew.bat │ └── settings.gradle.kts └── vertexai/ └── README.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ [*.{java,kt}] max_line_length = 120 ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: 🐞 Bug in the Firebase SDK url: https://github.com/firebase/firebase-android-sdk/issues/new/choose about: Do you think you have found a bug in the Firebase Android SDK? - name: 🤖 MLKit On-Device Issues url: https://github.com/googlesamples/mlkit about: The MLKit on-device SDK has moved out of Firebase and the best place to get support is on their samples repository. - name: 🔥 Firebase Support url: https://firebase.google.com/support/ about: If you have an urgent issue with your app, please contact support. ================================================ FILE: .github/ISSUE_TEMPLATE/quickstart_issue.md ================================================ --- name: ⚠️ Issue with the quickstart code about: Are you having issues running the code in this repository? --- ### Step 1: Describe your environment * Android device: _____ * Android OS version: _____ * Google Play Services version: _____ * Firebase/Play Services SDK version: _____ ### Step 2: Describe the problem: #### Steps to reproduce: 1. _____ 2. _____ 3. _____ #### Observed Results: * What happened? This could be a description, `logcat` output, etc. #### Expected Results: * What did you expect to happen? #### Relevant Code: ``` // TODO(you): code here to reproduce the problem ``` ================================================ FILE: .github/workflows/android.yml ================================================ name: Android CI on: pull_request: push: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true jobs: build: runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v3 with: distribution: 'zulu' java-version: 17 - name: Install Node to use the Firebase CLI uses: actions/setup-node@v6 with: node-version: 24 - name: Setup Gradle uses: gradle/gradle-build-action@v2 - name: Check Snippets run: python scripts/checksnippets.py - name: Copy mock google_services.json run: ./copy_mock_google_services_json.sh - name: Build with Gradle (Pull Request) run: ./build_pull_request.sh if: github.event_name == 'pull_request' - name: Build with Gradle (Push) run: ./gradlew clean ktlint assemble if: github.event_name != 'pull_request' ================================================ FILE: .gitignore ================================================ .gradle local.properties .idea build/ .DS_Store *.iml *.apk *.aar *.zip google-services.json .project .settings .classpath .vscode ================================================ FILE: .google/packaging.yaml ================================================ # GOOGLE SAMPLE PACKAGING DATA # # This file is used by Google as part of our samples packaging process. # End users may safely ignore this file. It has no relevance to other systems. --- status: PUBLISHED technologies: [Android, Firebase] categories: [Getting Started] languages: [Java] solutions: [Mobile, Monetization, Startup, Enterprise] github: firebase/quickstart-android branch: master level: BEGINNER icon: .google/icon.png license: apache2 ================================================ FILE: .opensource/project.json ================================================ { "name": "Firebase Quickstarts for Android", "parent": "quickstarts", "type": "sample", "platforms": [ "Android" ], "content": "README.md", "pages" : { "admob/README.md": "Admob", "analytics/README.md": "Analytics", "appdistribution/README.md": "App Distribution", "app-indexing/README.md": "App Indexing", "auth/README.md": "Authentication", "config/README.md": "Remote Config", "crash/README.md": "Crashlytics", "database/README.md": "Realtime Database", "dynamiclinks/README.md": "Dynamic Links", "firestore/README.md": "Firestore", "functions/README.md": "Cloud Functions", "inappmessaging/README.md": "In App Messaging", "messaging/README.md": "Cloud Messaging", "mlkit/README.md": "ML Kit", "perf/README.md": "Performance Monitoring", "storage/README.md": "Cloud Storage" }, "related": [ "firebase/quickstart-ios", "firebase/quickstart-js" ], "tags": [] } ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to the Firebase Android Quickstarts We'd love for you to contribute to our source code and to make the Firebase Android Quickstarts even better than it is today! Here are the guidelines we'd like you to follow: - [Code of Conduct](#coc) - [Question or Problem?](#question) - [Issues and Bugs](#issue) - [Feature Requests](#feature) - [Submission Guidelines](#submit) - [Coding Rules](#rules) - [Signing the CLA](#cla) ## Code of Conduct As contributors and maintainers of the Firebase Android Quickstarts project, we pledge to respect everyone who contributes by posting issues, updating documentation, submitting pull requests, providing feedback in comments, and any other activities. Communication through any of Firebase's channels (GitHub, StackOverflow, Google+, Twitter, etc.) must be constructive and never resort to personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. We promise to extend courtesy and respect to everyone involved in this project regardless of gender, gender identity, sexual orientation, disability, age, race, ethnicity, religion, or level of experience. We expect anyone contributing to the project to do the same. If any member of the community violates this code of conduct, the maintainers of the Firebase Android Quickstarts project may take action, removing issues, comments, and PRs or blocking accounts as deemed appropriate. If you are subject to or witness unacceptable behavior, or have any other concerns, please drop us a line at nivco@google.com. ## Got a Question or Problem? If you have questions about how to use the Firebase Android Quickstarts, please direct these to [StackOverflow][stackoverflow] and use the `firebase` tag. We are also available on GitHub issues. If you feel that we're missing an important bit of documentation, feel free to file an issue so we can help. Here's an example to get you started: ``` What are you trying to do or find out more about? Where have you looked? Where did you expect to find this information? ``` ## Found an Issue? If you find a bug in the source code or a mistake in the documentation, you can help us by submitting an issue to our [GitHub Repository][github]. Even better you can submit a Pull Request with a fix. See [below](#submit) for some guidelines. ## Submission Guidelines ### Submitting an Issue Before you submit your issue search the archive, maybe your question was already answered. If your issue appears to be a bug, and hasn't been reported, open a new issue. Please fill out all information in the issue template to maximize the chance that we can help you. **If you get help, help others. Good karma rulez!** ### Submitting a Pull Request Before you submit your pull request consider the following guidelines: * Search [GitHub](https://github.com/firebase/firebase-quickstart-web/pulls) for an open or closed Pull Request that relates to your submission. You don't want to duplicate effort. * Please sign our [Contributor License Agreement (CLA)](#cla) before sending pull requests. We cannot accept code without this. * Make your changes in a new git branch: ```shell $ git checkout -b my-fix-branch master ``` * Create your patch, **including appropriate test cases**. * Follow our [Coding Rules](#rules). * Avoid checking in files that shouldn't be tracked (e.g `*.class`, `.idea`, `.tmp`). We recommend using a [global](#global-gitignore) gitignore for this. * Commit your changes using a descriptive commit message. ```shell $ git commit -a ``` Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files. * Build your changes locally to ensure all the tests pass: ```shell $ ./gradlew build ``` * Push your branch to GitHub: ```shell $ git push origin my-fix-branch ``` * In GitHub, send a pull request to `firebase-quickstart-android:master`. * If we suggest changes then: * Make the required updates. * Rebase your branch and force push to your GitHub repository (this will update your Pull Request): ```shell $ git rebase master -i $ git push origin my-fix-branch -f ``` That's it! Thank you for your contribution! #### After your pull request is merged After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository: * Delete the remote branch on GitHub either through the GitHub Android UI or your local shell as follows: ```shell $ git push origin --delete my-fix-branch ``` * Check out the master branch: ```shell $ git checkout master -f ``` * Delete the local branch: ```shell $ git branch -D my-fix-branch ``` * Update your master with the latest upstream version: ```shell $ git pull --ff upstream master ``` ## Coding Rules Try to follow the same code style you see in the repository. ## Signing the CLA Please sign our [Contributor License Agreement][google-cla] (CLA) before sending pull requests. For any code changes to be accepted, the CLA must be signed. It's a quick process, we promise! *This guide was inspired by the [AngularJS contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).* [github]: https://github.com/firebase/quickstart-android [google-cla]: https://cla.developers.google.com [stackoverflow]: http://stackoverflow.com/questions/tagged/firebase [global-gitignore]: https://help.github.com/articles/ignoring-files/#create-a-global-gitignore ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2017 Google Inc Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. All code in any directories or sub-directories that end with *.html or *.css is licensed under the Creative Commons Attribution International 4.0 License, which full text can be found here: https://creativecommons.org/licenses/by/4.0/legalcode. As an exception to this license, all html or css that is generated by the software at the direction of the user is copyright the user. The user has full ownership and control over such content, including whether and how they wish to license it. ================================================ FILE: README.md ================================================ # Firebase Quickstarts for Android A collection of quickstart samples demonstrating the Firebase APIs on Android. For more information, see https://firebase.google.com. ## Samples You can open each of the following samples as an Android Studio project, and run them on a mobile device or a virtual device (AVD). When doing so you need to add each sample app you wish to try to a Firebase project on the [Firebase console](https://console.firebase.google.com). You can add multiple sample apps to the same Firebase project. There's no need to create separate projects for each app. To add a sample app to a Firebase project, use the `applicationId` value specified in the `app/build.gradle` file of the app as the Android package name. Download the generated `google-services.json` file, and copy it to the `app/` directory of the sample you wish to run. - [Admob](admob/README.md) - [Firebase AI Logic](firebase-ai/README.md) - [Analytics](analytics/README.md) - [App Distribution](appdistribution/README.md) - [Auth](auth/README.md) - [Remote Config](config/README.md) - [Crashlytics](crash/README.md) - [Realtime Database](database/README.md) - [Data Connect](dataconnect/README.md) - [Firestore](firestore/README.md) - [Cloud Functions for Firebase](functions/README.md) - [In-App Messaging](inappmessaging/README.md) - [Cloud Messaging](messaging/README.md) - [Performance Monitoring](perf/README.md) - [Cloud Storage for Firebase](storage/README.md) ## How to make contributions? Please read and follow the steps in the [CONTRIBUTING.md](CONTRIBUTING.md) [![Actions Status][gh-actions-badge]][gh-actions] [![SAM Score][sam-score-badge]][sam-score] [gh-actions]: https://github.com/firebase/quickstart-android/actions [gh-actions-badge]: https://github.com/firebase/quickstart-android/actions/workflows/android.yml/badge.svg?branch=master&event=push [sam-score]: https://ossbot.computer/samscore.html [sam-score-badge]: https://ossbot.computer/samscorebadge?org=firebase&repo=quickstart-android ================================================ FILE: admob/.gitignore ================================================ .gradle /local.properties .DS_Store build/ google-services.json # Android Studio .idea *.iml ================================================ FILE: admob/.google/packaging.yaml ================================================ # GOOGLE SAMPLE PACKAGING DATA # # This file is used by Google as part of our samples packaging process. # End users may safely ignore this file. It has no relevance to other systems. --- # Values: {DRAFT | PUBLISHED | INTERNAL | DEPRECATED | SUPERCEDED} status: DRAFT # Optional, put additional explanation here for DEPRECATED or SUPERCEDED. # statusNote: # See http://go/sample-categories technologies: [Android, Google Play Services, Google AdMob] categories: [Getting Started] languages: [Java] solutions: [Mobile] # May be omitted if unpublished # github: google/actionbar-basics # Values: BEGINNER | INTERMEDIATE | ADVANCED | EXPERT level: BEGINNER # Dimensions: 512x512, PNG fomrat icon: app/src/main/res/drawable/ic_launcher_big.png # List of APIs that this sample should be listed under. Use authoritive, # names that are unique for the product in question. Examples: # # Android - android: # App Engine - gae-java: # gae-python: # Web Services - ws: apiRefs: - android:com.google.android.gms.ads # Default: apache2. May be omitted for most samples. # Alternatives: apache2-android (for AOSP) license: apache2 ================================================ FILE: admob/README.md ================================================ AdMob by Google Quickstart ======================= The AdMob by Google Android quickstart demonstrates how to display an interstitial ad and a banner ad. AdRequest and AdView are used to display a banner ad and InterstitialAd is used to display the interstitial ad. Introduction ------------ - [Read more about AdMob by Google](https://firebase.google.com/docs/admob/) Getting Started --------------- - [Add Firebase to your Android Project](https://firebase.google.com/docs/android/setup). - Configure your AdMob app id: - In `src/main/res/values/strings.xml` change the `admob_app_id` string to your AdMob app id. - Note that this ID is used in two places: `AndroidManifest.xml` and `MainActivity` - Run the sample on your Android device or emulator. - The running sample displays a test banner ad and a test interstitial ad. Result ----------- Support ------- - [Stack Overflow](https://stackoverflow.com/questions/tagged/admob) - [Developer Forum](https://groups.google.com/group/google-admob-ads-sdk) - [Firebase Support](https://firebase.google.com/support/) License ------- Copyright 2016 Google, Inc. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: admob/app/build.gradle.kts ================================================ import com.android.build.gradle.internal.tasks.factory.dependsOn plugins { alias(libs.plugins.android.application) alias(libs.plugins.google.services) } tasks { check.dependsOn("assembleDebugAndroidTest") } android { namespace = "com.google.samples.quickstart.admobexample" compileSdk = 36 defaultConfig { applicationId = "com.google.samples.quickstart.admobexample" minSdk = 23 targetSdk = 36 versionCode = 1 versionName = "1.0" multiDexEnabled = true testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { getByName("release") { isMinifyEnabled = false proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } packaging { resources.excludes += "LICENSE.txt" } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } buildFeatures { viewBinding = true } } dependencies { implementation(project(":internal:lintchecks")) implementation(project(":internal:chooserx")) implementation("androidx.appcompat:appcompat:1.7.1") implementation("com.google.android.material:material:1.13.0") implementation("androidx.browser:browser:1.5.0") implementation("androidx.navigation:navigation-fragment-ktx:2.9.6") implementation("androidx.navigation:navigation-ui-ktx:2.9.6") implementation("com.google.android.gms:play-services-ads:23.3.0") // Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom) implementation(platform("com.google.firebase:firebase-bom:34.7.0")) // For an optimal experience using AdMob, add the Firebase SDK // for Google Analytics. This is recommended, but not required. implementation("com.google.firebase:firebase-analytics") debugImplementation("androidx.fragment:fragment-testing:1.8.9") androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0") androidTestImplementation("androidx.test:rules:1.7.0") androidTestImplementation("androidx.test:runner:1.7.0") androidTestImplementation("androidx.test.ext:junit:1.3.0") } ================================================ FILE: admob/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} -keepattributes EnclosingMethod -keepattributes InnerClasses ================================================ FILE: admob/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/EntryChoiceActivity.kt ================================================ package com.google.samples.quickstart.admobexample import android.content.Intent import com.firebase.example.internal.BaseEntryChoiceActivity import com.firebase.example.internal.Choice class EntryChoiceActivity : BaseEntryChoiceActivity() { override fun getChoices(): List { return listOf( Choice( "Java", "Run the Firebase Admob quickstart written in Java.", Intent(this, com.google.samples.quickstart.admobexample.java.MainActivity::class.java), ), Choice( "Kotlin", "Run the Firebase Admob quickstart written in Kotlin.", Intent(this, com.google.samples.quickstart.admobexample.kotlin.MainActivity::class.java), ), ) } } ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/java/FirstFragment.java ================================================ package com.google.samples.quickstart.admobexample.java; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.navigation.fragment.NavHostFragment; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import com.google.android.gms.ads.FullScreenContentCallback; import com.google.android.gms.ads.LoadAdError; import com.google.android.gms.ads.MobileAds; import com.google.android.gms.ads.interstitial.InterstitialAd; import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback; import com.google.samples.quickstart.admobexample.R; import com.google.samples.quickstart.admobexample.databinding.FragmentFirstBinding; class FirstFragment extends Fragment { private static final String TAG = "MainActivity"; private static final String TEST_APP_ID = "ca-app-pub-3940256099942544~3347511713"; private AdView mAdView; private InterstitialAd mInterstitialAd; private Button mLoadInterstitialButton; private FragmentFirstBinding binding; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { binding = FragmentFirstBinding.inflate(inflater, container, false); return binding.getRoot(); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); checkIds(); // Initialize the Google Mobile Ads SDK MobileAds.initialize(getContext()); mAdView = binding.adView; requestNewInterstitial(); mLoadInterstitialButton = binding.loadInterstitialButton; mLoadInterstitialButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mInterstitialAd != null) { mInterstitialAd.show(getActivity()); } else { beginSecondActivity(); } } }); // Disable button if an interstitial ad is not loaded yet. mLoadInterstitialButton.setEnabled(mInterstitialAd != null); } /** * Load a new interstitial ad asynchronously. */ private void requestNewInterstitial() { AdRequest adRequest = new AdRequest.Builder().build(); mAdView.loadAd(adRequest); // AdMob ad unit IDs are not currently stored inside the google-services.json file. // Developers using AdMob can store them as custom values in a string resource file or // simply use constants. Note that the ad units used here are configured to return only test // ads, and should not be used outside this sample. InterstitialAd.load(getContext(), getString(R.string.interstitial_ad_unit_id), adRequest, new InterstitialAdLoadCallback() { @Override public void onAdLoaded(@NonNull InterstitialAd interstitialAd) { super.onAdLoaded(interstitialAd); mInterstitialAd = interstitialAd; // Ad received, ready to display if (mLoadInterstitialButton != null) { mLoadInterstitialButton.setEnabled(true); } mInterstitialAd.setFullScreenContentCallback(new FullScreenContentCallback() { @Override public void onAdDismissedFullScreenContent() { super.onAdDismissedFullScreenContent(); requestNewInterstitial(); beginSecondActivity(); } }); } @Override public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { super.onAdFailedToLoad(loadAdError); mInterstitialAd = null; Log.w(TAG, "onAdFailedToLoad:" + loadAdError.getMessage()); } }); } private void beginSecondActivity() { NavHostFragment.findNavController(this).navigate(R.id.action_FirstFragment_to_SecondFragment); } /** Called when leaving the activity */ @Override public void onPause() { if (mAdView != null) { mAdView.pause(); } super.onPause(); } /** Called when returning to the activity */ @Override public void onResume() { super.onResume(); if (mAdView != null) { mAdView.resume(); } if (mInterstitialAd == null) { requestNewInterstitial(); } } /** Called before the activity is destroyed */ @Override public void onDestroy() { if (mAdView != null) { mAdView.destroy(); } super.onDestroy(); } @VisibleForTesting public AdView getAdView() { return mAdView; } private void checkIds() { if (TEST_APP_ID.equals(getString(R.string.admob_app_id))) { Log.w(TAG, "Your admob_app_id is not configured correctly, please see the README"); } } } ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/java/MainActivity.java ================================================ /** * Copyright Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.samples.quickstart.admobexample.java; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import androidx.navigation.Navigation; import com.google.samples.quickstart.admobexample.R; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Navigation.findNavController(this, R.id.nav_host_fragment).setGraph(R.navigation.nav_graph_java); } } ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/java/SecondFragment.java ================================================ package com.google.samples.quickstart.admobexample.java; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.fragment.app.Fragment; import com.google.samples.quickstart.admobexample.R; class SecondFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_second, container, false); } } ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/FirstFragment.kt ================================================ package com.google.samples.quickstart.admobexample.kotlin import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.Button import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.google.android.gms.ads.AdRequest import com.google.android.gms.ads.AdView import com.google.android.gms.ads.FullScreenContentCallback import com.google.android.gms.ads.LoadAdError import com.google.android.gms.ads.MobileAds import com.google.android.gms.ads.interstitial.InterstitialAd import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback import com.google.samples.quickstart.admobexample.R import com.google.samples.quickstart.admobexample.databinding.FragmentFirstBinding class FirstFragment : Fragment() { private var _binding: FragmentFirstBinding? = null private val binding get() = _binding!! private var interstitialAd: InterstitialAd? = null private lateinit var adView: AdView private lateinit var loadInterstitialButton: Button override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { _binding = FragmentFirstBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) adView = binding.adView loadInterstitialButton = binding.loadInterstitialButton checkIds() // Initialize the Google Mobile Ads SDK MobileAds.initialize(requireContext()) requestNewInterstitial() loadInterstitialButton.setOnClickListener { if (interstitialAd != null) { interstitialAd?.show(requireActivity()) } else { goToNextFragment() } } // Disable button if an interstitial ad is not loaded yet. loadInterstitialButton.isEnabled = interstitialAd != null } /** * Load a new interstitial ad asynchronously. */ private fun requestNewInterstitial() { // AdMob ad unit IDs are not currently stored inside the google-services.json file. // Developers using AdMob can store them as custom values in a string resource file or // simply use constants. Note that the ad units used here are configured to return only test // ads, and should not be used outside this sample. val adRequest = AdRequest.Builder().build() adView.loadAd(adRequest) InterstitialAd.load( requireContext(), getString(R.string.interstitial_ad_unit_id), adRequest, object : InterstitialAdLoadCallback() { override fun onAdLoaded(ad: InterstitialAd) { super.onAdLoaded(ad) interstitialAd = ad // Ad received, ready to display loadInterstitialButton.isEnabled = true interstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() { override fun onAdDismissedFullScreenContent() { super.onAdDismissedFullScreenContent() goToNextFragment() } } } override fun onAdFailedToLoad(error: LoadAdError) { super.onAdFailedToLoad(error) interstitialAd = null Log.w(TAG, "onAdFailedToLoad:${error.message}") } }, ) } private fun goToNextFragment() { findNavController().navigate(R.id.action_FirstFragment_to_SecondFragment) } /** Called when leaving the activity */ override fun onPause() { adView.pause() super.onPause() } /** Called when returning to the activity */ override fun onResume() { super.onResume() adView.resume() if (interstitialAd == null) { requestNewInterstitial() } } /** Called before the activity is destroyed */ override fun onDestroy() { adView.destroy() super.onDestroy() } private fun checkIds() { if (TEST_APP_ID == getString(R.string.admob_app_id)) { Log.w(TAG, "Your admob_app_id is not configured correctly, please see the README") } } companion object { private const val TAG = "FirstFragment" private const val TEST_APP_ID = "ca-app-pub-3940256099942544~3347511713" } override fun onDestroyView() { super.onDestroyView() _binding = null } } ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/MainActivity.kt ================================================ package com.google.samples.quickstart.admobexample.kotlin import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.navigation.findNavController import com.google.samples.quickstart.admobexample.R class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findNavController(R.id.nav_host_fragment).setGraph(R.navigation.nav_graph_kotlin) } } ================================================ FILE: admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/SecondFragment.kt ================================================ package com.google.samples.quickstart.admobexample.kotlin import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment import com.google.samples.quickstart.admobexample.R class SecondFragment : Fragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_second, container, false) } } ================================================ FILE: admob/app/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: admob/app/src/main/res/layout/fragment_first.xml ================================================
Token:

ADB Command:
          
================================================ FILE: build.gradle.kts ================================================ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.google.services) apply false alias(libs.plugins.firebase.crashlytics) apply false alias(libs.plugins.firebase.perf) apply false alias(libs.plugins.navigation.safeargs) apply false alias(libs.plugins.gradle.versions) apply true alias(libs.plugins.compose.compiler) apply false } allprojects { repositories { google() mavenLocal() mavenCentral() } } val ktlint by configurations.creating dependencies { ktlint("com.pinterest:ktlint:0.49.1") { attributes { attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) } } } tasks.register("ktlintCheck") { val outputDir = "${project.layout.buildDirectory}/reports/ktlint/" val inputFiles = project.fileTree("src").include("**/*.kt") val outputFile = "${outputDir}ktlint-checkstyle-report.xml" // See: https://medium.com/@vanniktech/making-your-gradle-tasks-incremental-7f26e4ef09c3 inputs.files(inputFiles) outputs.file(outputFile) group = LifecycleBasePlugin.VERIFICATION_GROUP description = "Check Kotlin code style" classpath = ktlint mainClass.set("com.pinterest.ktlint.Main") args( "--format", "--code-style=android_studio", "--reporter=plain", "--reporter=checkstyle,output=${outputFile}", "**/*.kt", "!**/build/**" ) jvmArgs("--add-opens=java.base/java.lang=ALL-UNNAMED") } fun notFromFirebase(candidate: ModuleComponentIdentifier): Boolean { return candidate.group != "com.google.firebase" } fun isNonStable(candidate: ModuleComponentIdentifier): Boolean { return listOf("alpha", "beta", "rc", "snapshot", "-m", "final").any { keyword -> keyword in candidate.version.lowercase() } } fun isBlockListed(candidate: ModuleComponentIdentifier): Boolean { return listOf( "androidx.browser:browser", "androidx.webkit:webkit", "com.facebook.android", "com.google.guava", "com.github.bumptech.glide" ).any { keyword -> keyword in candidate.toString().lowercase() } } tasks.withType { rejectVersionIf { (isNonStable(candidate) && notFromFirebase(candidate)) || isBlockListed(candidate) } } tasks { register("clean", Delete::class) { delete(rootProject.layout.buildDirectory) } } ================================================ FILE: build_pull_request.sh ================================================ #!/bin/bash # Exit on error set -e # unshallow since GitHub actions does a shallow clone git fetch --unshallow git fetch origin # Get all the modules that were changed while read line; do module_name=${line%%/*} if [[ ${MODULES} != *"${module_name}" ]]; then MODULES="${MODULES} ${module_name}" fi done < <(git diff --name-only origin/$GITHUB_BASE_REF) changed_modules=$MODULES # Get a list of all available gradle tasks AVAILABLE_TASKS=$(./gradlew tasks --all) # Check if these modules have gradle tasks build_commands="" for module in $changed_modules do if [[ $AVAILABLE_TASKS =~ $module":app:" ]]; then build_commands=${build_commands}" :"${module}":app:assembleDebug :"${module}":app:check" fi done # Build echo "Building Pull Request with" echo $build_commands eval "./gradlew clean ktlint ${build_commands}" ================================================ FILE: config/README.md ================================================ Firebase Remote Config Quickstart ============================== The Firebase Remote Config Android quickstart app demonstrates using Remote Config to define user-facing text in an Android app. Introduction ------------ This is a simple example of using Remote Config to override in-app default values by defining service-side parameter values in the Firebase console. This example demonstrates a small subset of the capabilities of Firebase Remote Config. To learn more about how you can use Firebase Remote Config in your app, see [Firebase Remote Config Introduction](https://firebase.google.com/docs/remote-config/). Getting started --------------- 1. [Add Firebase to your Android Project](https://firebase.google.com/docs/android/setup). 2. [Create a Remote Config project for the quickstart sample](https://firebase.google.com/docs/remote-config/android#create_a_product_name_project_for_the_quickstart_sample), defining the parameter values and parameter keys used by the sample. 3. Run the sample on an Android device or emulator. 4. Change one or more parameter values in the Firebase Console (the value of `welcome_message`, `welcome_message_caps`, or both). 5. Tap **Fetch Remote Config** in the app to fetch new parameter values and see the resulting change in the app. Best practices -------------- This section provides some additional information about how the quickstart example sets in-app default parameter values and fetches values from the Remote Config service ### In-app default parameter values ### In-app default values are set using an XML file in this example, but you can also set in-app default values inline using other `setDefault` methods of the [`FirebaseRemoteConfig` class](https://firebase.google.com/docs/reference/android/com/google/firebase/remoteconfig/FirebaseRemoteConfig#public-method-summary). Then, you can override only those values that you need to change from the Firebase console. This lets you use Remote Config for any default value that you might want to override in the future, without the need to set all of those values in the Firebase console. ### Fetch values from the Remote Config service ### When an app calls `fetch`, locally stored parameter values are used unless the minimum fetch interval is reached. The minimal fetch interval is determined by: 1. The parameter passed to `fetch(long minFetchInterval)`. 2. The minimum fetch interval set in Remote Config settings. 3. The default minimum fetch interval, 12 hours. Fetched values are immediately activated when retrieved using `fetchAndActivate`. `fetchAndActivate` returns true if the final set of key/value pairs now available to the application is different to the set before calling `fetchAndActivate`, false is returned otherwise. In the quickstart sample app, you call `fetchAndActivate` from the UI by tapping **Fetch Remote Config**. To control when fetched values are activated and available to your app use `fetch`, the values are locally stored, but not immediately activated. To activate fetched values so that they take effect, call the `activate` method. You can also create a Remote Config Setting to enable developer mode, but you must remove this setting before distributing your app. Fetching Remote Config data from the service is normally limited to a few requests per hour. By enabling developer mode, you can make many more requests per hour, so you can test your app with different Remote Config parameter values during development. - To learn more about fetching data from remote config, see the Remote Config Frequently Asked Question (FAQ) on [fetching and activating parameter values](https://firebase.google.com/support/faq#remote-config-values). - To learn about parameters and conditions that you can use to change the behavior and appearance of your app for segments of your userbase, see [Remote Config Parameters and Conditions](https://firebase.google.com/docs/remote-config/parameters). - To learn more about the Remote Config API, see [Remote Config API Overview](https://firebase.google.com/docs/remote-config/api-overview). Result ----------- Support ------- - [Stack Overflow](https://stackoverflow.com/questions/tagged/firebase-remote-config) - [Firebase Support](https://firebase.google.com/support/) License ------- Copyright 2016 Google, Inc. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: config/app/build.gradle.kts ================================================ import com.android.build.gradle.internal.tasks.factory.dependsOn plugins { alias(libs.plugins.android.application) alias(libs.plugins.google.services) } tasks { check.dependsOn("assembleDebugAndroidTest") } android { namespace = "com.google.samples.quickstart.config" compileSdk = 36 defaultConfig { applicationId = "com.google.samples.quickstart.config" minSdk = 23 targetSdk = 36 versionCode = 1 versionName = "1.0" multiDexEnabled = true testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { getByName("release") { isMinifyEnabled = false proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } buildFeatures { viewBinding = true } } dependencies { implementation(project(":internal:lintchecks")) implementation(project(":internal:chooserx")) implementation("com.google.android.material:material:1.13.0") // Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom) implementation(platform("com.google.firebase:firebase-bom:34.7.0")) // Firebase Remote Config implementation("com.google.firebase:firebase-config") // For an optimal experience using Remote Config, add the Firebase SDK // for Google Analytics. This is recommended, but not required. implementation("com.google.firebase:firebase-analytics") androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0") androidTestImplementation("androidx.test:rules:1.7.0") androidTestImplementation("androidx.test:runner:1.7.0") androidTestImplementation("androidx.test.ext:junit:1.3.0") } ================================================ FILE: config/app/proguard-rules.pro ================================================ # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the proguardFiles # directive in build.gradle.kts. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} -keepattributes EnclosingMethod -keepattributes InnerClasses ================================================ FILE: config/app/src/androidTest/java/com/google/samples/quickstart/config/MainActivityTest.java ================================================ package com.google.samples.quickstart.config; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.rule.ActivityTestRule; import androidx.test.filters.LargeTest; import com.google.samples.quickstart.config.java.MainActivity; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import static androidx.test.espresso.Espresso.onView; import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.assertion.ViewAssertions.matches; import static androidx.test.espresso.matcher.RootMatchers.withDecorView; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.Matchers.is; @LargeTest @RunWith(AndroidJUnit4.class) public class MainActivityTest { @Rule public ActivityTestRule rule = new ActivityTestRule<>(MainActivity.class); @Test public void testFetchConfig() { // Click fetch config button onView(withText(R.string.fetch_remote_welcome_message)) .check(matches(isDisplayed())) .perform(click()); // Watch for success Toast onView(withText(startsWith("Fetch Succeeded"))) .inRoot(withDecorView(not(is(rule.getActivity().getWindow().getDecorView())))) .check(matches(isDisplayed())); } } ================================================ FILE: config/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt ================================================ package com.google.samples.quickstart.config import android.content.Intent import com.firebase.example.internal.BaseEntryChoiceActivity import com.firebase.example.internal.Choice class EntryChoiceActivity : BaseEntryChoiceActivity() { override fun getChoices(): List { return listOf( Choice( "Java", "Run the Firebase Remote Config quickstart written in Java.", Intent( this, com.google.samples.quickstart.config.java.MainActivity::class.java, ), ), Choice( "Kotlin", "Run the Firebase Remote Config quickstart written in Kotlin.", Intent( this, com.google.samples.quickstart.config.kotlin.MainActivity::class.java, ), ), ) } } ================================================ FILE: config/app/src/main/java/com/google/samples/quickstart/config/java/MainActivity.java ================================================ /* * Copyright Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * For more information on setting up and running this sample code, see * https://firebase.google.com/docs/remote-config/android */ package com.google.samples.quickstart.config.java; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.remoteconfig.FirebaseRemoteConfig; import com.google.firebase.remoteconfig.FirebaseRemoteConfigException; import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings; import com.google.samples.quickstart.config.R; import com.google.samples.quickstart.config.databinding.ActivityMainBinding; import com.google.firebase.remoteconfig.ConfigUpdateListener; import com.google.firebase.remoteconfig.ConfigUpdate; public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; // Remote Config keys private static final String LOADING_PHRASE_CONFIG_KEY = "loading_phrase"; private static final String WELCOME_MESSAGE_KEY = "welcome_message"; private static final String WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps"; private FirebaseRemoteConfig mFirebaseRemoteConfig; private ActivityMainBinding mBinding; private TextView mWelcomeTextView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mBinding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(mBinding.getRoot()); mWelcomeTextView = mBinding.welcomeTextView; mBinding.fetchButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { fetchWelcome(); } }); // Get Remote Config instance. // [START get_remote_config_instance] mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance(); // [END get_remote_config_instance] // Create a Remote Config Setting to enable developer mode, which you can use to increase // the number of fetches available per hour during development. Also use Remote Config // Setting to set the minimum fetch interval. // [START enable_dev_mode] FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder() .setMinimumFetchIntervalInSeconds(3600) .build(); mFirebaseRemoteConfig.setConfigSettingsAsync(configSettings); // [END enable_dev_mode] // Set default Remote Config parameter values. An app uses the in-app default values, and // when you need to adjust those defaults, you set an updated value for only the values you // want to change in the Firebase console. See Best Practices in the README for more // information. // [START set_default_values] mFirebaseRemoteConfig.setDefaultsAsync(R.xml.remote_config_defaults); // [END set_default_values] // [START add_config_update_listener] mFirebaseRemoteConfig.addOnConfigUpdateListener(new ConfigUpdateListener() { @Override public void onUpdate(ConfigUpdate configUpdate) { Log.d(TAG, "Updated keys: " + configUpdate.getUpdatedKeys()); if (configUpdate.getUpdatedKeys().contains(WELCOME_MESSAGE_KEY)) { mFirebaseRemoteConfig.activate().addOnCompleteListener(new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { displayWelcomeMessage(); } }); } } @Override public void onError(FirebaseRemoteConfigException error) { Log.w(TAG, "Config update error with code: " + error.getCode(), error); } }); // [END add_config_update_listener] fetchWelcome(); } /** * Fetch a welcome message from the Remote Config service, and then activate it. */ private void fetchWelcome() { mWelcomeTextView.setText(mFirebaseRemoteConfig.getString(LOADING_PHRASE_CONFIG_KEY)); // [START fetch_config_with_callback] mFirebaseRemoteConfig.fetchAndActivate() .addOnCompleteListener(this, new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { boolean updated = task.getResult(); Log.d(TAG, "Config params updated: " + updated); Toast.makeText(MainActivity.this, "Fetch and activate succeeded", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "Fetch failed", Toast.LENGTH_SHORT).show(); } displayWelcomeMessage(); } }); // [END fetch_config_with_callback] } /** * Display a welcome message in all caps if welcome_message_caps is set to true. Otherwise, * display a welcome message as fetched from welcome_message. */ // [START display_welcome_message] private void displayWelcomeMessage() { // [START get_config_values] String welcomeMessage = mFirebaseRemoteConfig.getString(WELCOME_MESSAGE_KEY); // [END get_config_values] if (mFirebaseRemoteConfig.getBoolean(WELCOME_MESSAGE_CAPS_KEY)) { mWelcomeTextView.setAllCaps(true); } else { mWelcomeTextView.setAllCaps(false); } mWelcomeTextView.setText(welcomeMessage); } // [END display_welcome_message] } ================================================ FILE: config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt ================================================ package com.google.samples.quickstart.config.kotlin import android.os.Bundle import android.util.Log import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import com.google.firebase.Firebase import com.google.firebase.remoteconfig.ConfigUpdate import com.google.firebase.remoteconfig.ConfigUpdateListener import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.FirebaseRemoteConfigException import com.google.firebase.remoteconfig.get import com.google.firebase.remoteconfig.remoteConfig import com.google.firebase.remoteconfig.remoteConfigSettings import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var remoteConfig: FirebaseRemoteConfig private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) binding.fetchButton.setOnClickListener { fetchWelcome() } // Get Remote Config instance. // [START get_remote_config_instance] remoteConfig = Firebase.remoteConfig // [END get_remote_config_instance] // Create a Remote Config Setting to enable developer mode, which you can use to increase // the number of fetches available per hour during development. Also use Remote Config // Setting to set the minimum fetch interval. // [START enable_dev_mode] val configSettings = remoteConfigSettings { minimumFetchIntervalInSeconds = 3600 } remoteConfig.setConfigSettingsAsync(configSettings) // [END enable_dev_mode] // Set default Remote Config parameter values. An app uses the in-app default values, and // when you need to adjust those defaults, you set an updated value for only the values you // want to change in the Firebase console. See Best Practices in the README for more // information. // [START set_default_values] remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) // [END set_default_values] // [START add_config_update_listener] remoteConfig.addOnConfigUpdateListener(object : ConfigUpdateListener { override fun onUpdate(configUpdate: ConfigUpdate) { Log.d(TAG, "Updated keys: " + configUpdate.updatedKeys) if (configUpdate.updatedKeys.contains(WELCOME_MESSAGE_KEY)) { remoteConfig.activate().addOnCompleteListener { displayWelcomeMessage() } } } override fun onError(error: FirebaseRemoteConfigException) { Log.w(TAG, "Config update error with code: " + error.code, error) } }) // [END add_config_update_listener] fetchWelcome() } /** * Fetch a welcome message from the Remote Config service, and then activate it. */ private fun fetchWelcome() { binding.welcomeTextView.text = remoteConfig[LOADING_PHRASE_CONFIG_KEY].asString() // [START fetch_config_with_callback] remoteConfig.fetchAndActivate() .addOnCompleteListener(this) { task -> if (task.isSuccessful) { val updated = task.result Log.d(TAG, "Config params updated: $updated") Toast.makeText( this, "Fetch and activate succeeded", Toast.LENGTH_SHORT, ).show() } else { Toast.makeText( this, "Fetch failed", Toast.LENGTH_SHORT, ).show() } displayWelcomeMessage() } // [END fetch_config_with_callback] } /** * Display a welcome message in all caps if welcome_message_caps is set to true. Otherwise, * display a welcome message as fetched from welcome_message. */ // [START display_welcome_message] private fun displayWelcomeMessage() { // [START get_config_values] val welcomeMessage = remoteConfig[WELCOME_MESSAGE_KEY].asString() // [END get_config_values] binding.welcomeTextView.isAllCaps = remoteConfig[WELCOME_MESSAGE_CAPS_KEY].asBoolean() binding.welcomeTextView.text = welcomeMessage } companion object { private const val TAG = "MainActivity" // Remote Config keys private const val LOADING_PHRASE_CONFIG_KEY = "loading_phrase" private const val WELCOME_MESSAGE_KEY = "welcome_message" private const val WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps" } // [END display_welcome_message] } ================================================ FILE: config/app/src/main/res/layout/activity_main.xml ================================================