├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── codelab-00 ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── playbilling │ │ │ └── trivialdrive │ │ │ └── kotlin │ │ │ ├── GameFragment.kt │ │ │ ├── MainActivity.kt │ │ │ └── MakePurchaseFragment.kt │ │ └── res │ │ ├── drawable-v24 │ │ ├── free_car.png │ │ ├── gas.png │ │ ├── gas_level_0.png │ │ ├── gas_level_1.png │ │ ├── gas_level_2.png │ │ ├── gas_level_3.png │ │ ├── gas_level_4.png │ │ ├── gold_status.png │ │ ├── gold_subs_icon.png │ │ ├── ic_launcher_foreground.xml │ │ ├── premium_car.png │ │ └── title.png │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_game.xml │ │ └── fragment_make_purchase.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── navigation_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystore.properties ├── kotlin_td_keystore.jks └── settings.gradle ├── codelab-01 ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── playbilling │ │ │ └── trivialdrive │ │ │ └── kotlin │ │ │ ├── GameFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MakePurchaseFragment.kt │ │ │ └── billingrepo │ │ │ ├── BillingRepository.kt │ │ │ └── localdb │ │ │ ├── AugmentedSkuDetails.kt │ │ │ ├── AugmentedSkuDetailsDao.kt │ │ │ ├── CachedPurchase.kt │ │ │ ├── Entitlements.kt │ │ │ ├── EntitlementsDao.kt │ │ │ ├── LocalBillingDb.kt │ │ │ └── PurchaseDao.kt │ │ └── res │ │ ├── drawable-v24 │ │ ├── free_car.png │ │ ├── gas.png │ │ ├── gas_level_0.png │ │ ├── gas_level_1.png │ │ ├── gas_level_2.png │ │ ├── gas_level_3.png │ │ ├── gas_level_4.png │ │ ├── gold_status.png │ │ ├── gold_subs_icon.png │ │ ├── ic_launcher_foreground.xml │ │ ├── premium_car.png │ │ └── title.png │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_game.xml │ │ └── fragment_make_purchase.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── navigation_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystore.properties ├── kotlin_td_keystore.jks └── settings.gradle ├── codelab-02 ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── playbilling │ │ │ └── trivialdrive │ │ │ └── kotlin │ │ │ ├── GameFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MakePurchaseFragment.kt │ │ │ └── billingrepo │ │ │ ├── BillingRepository.kt │ │ │ ├── BillingWebservice.kt │ │ │ ├── Security.kt │ │ │ └── localdb │ │ │ ├── AugmentedSkuDetails.kt │ │ │ ├── AugmentedSkuDetailsDao.kt │ │ │ ├── CachedPurchase.kt │ │ │ ├── Entitlements.kt │ │ │ ├── EntitlementsDao.kt │ │ │ ├── LocalBillingDb.kt │ │ │ └── PurchaseDao.kt │ │ └── res │ │ ├── drawable-v24 │ │ ├── free_car.png │ │ ├── gas.png │ │ ├── gas_level_0.png │ │ ├── gas_level_1.png │ │ ├── gas_level_2.png │ │ ├── gas_level_3.png │ │ ├── gas_level_4.png │ │ ├── gold_status.png │ │ ├── gold_subs_icon.png │ │ ├── ic_launcher_foreground.xml │ │ ├── premium_car.png │ │ └── title.png │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_game.xml │ │ └── fragment_make_purchase.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── navigation_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystore.properties ├── kotlin_td_keystore.jks └── settings.gradle ├── codelab-03 ├── .gitignore ├── README.md ├── app │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── playbilling │ │ │ └── trivialdrive │ │ │ └── kotlin │ │ │ ├── GameFragment.kt │ │ │ ├── MainActivity.kt │ │ │ ├── MakePurchaseFragment.kt │ │ │ ├── billingrepo │ │ │ ├── BillingRepository.kt │ │ │ ├── BillingWebservice.kt │ │ │ ├── Security.kt │ │ │ └── localdb │ │ │ │ ├── AugmentedSkuDetails.kt │ │ │ │ ├── AugmentedSkuDetailsDao.kt │ │ │ │ ├── CachedPurchase.kt │ │ │ │ ├── Entitlements.kt │ │ │ │ ├── EntitlementsDao.kt │ │ │ │ ├── LocalBillingDb.kt │ │ │ │ └── PurchaseDao.kt │ │ │ └── viewmodels │ │ │ └── BillingViewModel.kt │ │ └── res │ │ ├── drawable-v24 │ │ ├── free_car.png │ │ ├── gas.png │ │ ├── gas_level_0.png │ │ ├── gas_level_1.png │ │ ├── gas_level_2.png │ │ ├── gas_level_3.png │ │ ├── gas_level_4.png │ │ ├── gold_status.png │ │ ├── gold_subs_icon.png │ │ ├── ic_launcher_foreground.xml │ │ ├── premium_car.png │ │ └── title.png │ │ ├── drawable │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_game.xml │ │ └── fragment_make_purchase.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── navigation │ │ └── navigation_graph.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystore.properties ├── kotlin_td_keystore.jks └── settings.gradle └── codelab-04 ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── playbilling │ │ └── trivialdrive │ │ └── kotlin │ │ ├── GameFragment.kt │ │ ├── MainActivity.kt │ │ ├── MakePurchaseFragment.kt │ │ ├── adapters │ │ └── InventoryAdapter.kt │ │ ├── billingrepo │ │ ├── BillingRepository.kt │ │ ├── BillingWebservice.kt │ │ ├── Security.kt │ │ └── localdb │ │ │ ├── AugmentedSkuDetails.kt │ │ │ ├── AugmentedSkuDetailsDao.kt │ │ │ ├── CachedPurchase.kt │ │ │ ├── Entitlements.kt │ │ │ ├── EntitlementsDao.kt │ │ │ ├── LocalBillingDb.kt │ │ │ └── PurchaseDao.kt │ │ └── viewmodels │ │ └── BillingViewModel.kt │ └── res │ ├── drawable-v24 │ ├── free_car.png │ ├── gas.png │ ├── gas_level_0.png │ ├── gas_level_1.png │ ├── gas_level_2.png │ ├── gas_level_3.png │ ├── gas_level_4.png │ ├── gold_status.png │ ├── gold_subs_icon.png │ ├── ic_launcher_foreground.xml │ ├── premium_car.png │ └── title.png │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ ├── activity_main.xml │ ├── fragment_game.xml │ ├── fragment_make_purchase.xml │ └── inventory_item.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── navigation │ └── navigation_graph.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── keystore.properties ├── kotlin_td_keystore.jks └── settings.gradle /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution, 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codelab: Scalable Implementation of Play Billing in Kotlin 2 | 3 | Sample application sources for Google Play Billing Codelab 4 | 5 | ## Introduction 6 | 7 | This sample is provided to demonstrate a scalable way of integrating with Google Play Billing. 8 | To read more please open the codelab page. 9 | 10 | ## Support 11 | 12 | If you've found an error in this sample, please file an issue: 13 | https://github.com/googlecodelabs/play-billing-scalable-kotlin/issues 14 | 15 | ## License 16 | 17 | Copyright 2019 Google, Inc. 18 | 19 | Licensed to the Apache Software Foundation (ASF) under one or more contributor 20 | license agreements. See the NOTICE file distributed with this work for 21 | additional information regarding copyright ownership. The ASF licenses this 22 | file to you under the Apache License, Version 2.0 (the "License"); you may not 23 | use this file except in compliance with the License. You may obtain a copy of 24 | the License at 25 | 26 | http://www.apache.org/licenses/LICENSE-2.0 27 | 28 | Unless required by applicable law or agreed to in writing, software 29 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 30 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 31 | License for the specific language governing permissions and limitations under 32 | the License. 33 | 34 | ## CHANGELOG 35 | 36 | -------------------------------------------------------------------------------- /codelab-00/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.idea/caches/build_file_checksums.ser 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | /app/release -------------------------------------------------------------------------------- /codelab-00/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /codelab-00/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | import android.os.Bundle 19 | import androidx.appcompat.app.AppCompatActivity 20 | import com.kotlin.trivialdrive.R 21 | 22 | class MainActivity : AppCompatActivity() { 23 | 24 | override fun onCreate(savedInstanceState: Bundle?) { 25 | super.onCreate(savedInstanceState) 26 | setContentView(R.layout.activity_main) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MakePurchaseFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | 19 | import android.os.Bundle 20 | import android.util.Log 21 | import android.view.LayoutInflater 22 | import android.view.View 23 | import android.view.ViewGroup 24 | import androidx.fragment.app.Fragment 25 | import androidx.recyclerview.widget.RecyclerView 26 | import com.kotlin.trivialdrive.R 27 | 28 | /** 29 | * This Fragment is simply a wrapper for the inventory (i.e. items for sale). It contains two 30 | * [lists][RecyclerView], one for subscriptions and one for in-app products. Here again there is 31 | * no complicated billing logic. All the billing logic reside inside the [BillingRepository]. 32 | * The [BillingRepository] provides a [AugmentedSkuDetails] object that shows what 33 | * is for sale and whether the user is allowed to buy the item at this moment. E.g. if the user 34 | * already has a full tank of gas, then they cannot buy gas at this moment. 35 | */ 36 | class MakePurchaseFragment : Fragment() { 37 | 38 | val LOG_TAG = "MakePurchaseFragment" 39 | 40 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 41 | return inflater.inflate(R.layout.fragment_make_purchase, container, false) 42 | } 43 | 44 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 45 | super.onViewCreated(view, savedInstanceState) 46 | Log.d(LOG_TAG, "onViewCreated") 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/free_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/free_car.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gas.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gas_level_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gas_level_0.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gas_level_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gas_level_1.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gas_level_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gas_level_2.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gas_level_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gas_level_3.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gas_level_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gas_level_4.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gold_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gold_status.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/gold_subs_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/gold_subs_icon.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/premium_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/premium_car.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/drawable-v24/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/drawable-v24/title.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/layout/fragment_make_purchase.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 29 | 35 | 38 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/navigation/navigation_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | 25 | 30 | 33 | 34 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | #008577 21 | #00574B 22 | #FFCA28 23 | #FFE082 24 | #FFECB3 25 | #CFD8DC 26 | #90A4AE 27 | #263238 28 | 29 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 16dp 21 | 8dp 22 | 32dp 23 | 8dp 24 | 8dp 25 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Trivial Drive Kotlin 19 | Hello blank fragment 20 | Fun Products 21 | Fun Subscriptions 22 | Vroooom, you drove a few miles! 23 | Oh, no! You are out of gas! Try buying some! 24 | 25 | -------------------------------------------------------------------------------- /codelab-00/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-00/build.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 18 | 19 | buildscript { 20 | ext { 21 | APP_ID = "com.isaidamier.kotlin.trivialdrive" 22 | 23 | //keystorePropertiesFilename lives in gradle.properties 24 | keystorePropertiesFile = rootProject.file(keystorePropertiesFilename) 25 | keystoreProperties = new Properties() 26 | if (keystorePropertiesFile.exists()) { 27 | keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) 28 | } else { 29 | println "Cannot find keystore properties file. " + 30 | "A) Create this file, B) use a different file, or C) use assembleDebug." 31 | println "A) Create $keystorePropertiesFilename" 32 | println "B) ./gradlew -PkeystorePropertiesFilename=release-keystore.properties assembleRelease" 33 | println "C) ./gradlew assembleDebug" 34 | println "" 35 | } 36 | keystoreFilename = keystoreProperties['storeFile'] 37 | //signing config values 38 | releaseStoreFile = keystoreFilename == null ? null : rootProject.file(keystoreFilename) 39 | releaseStorePassword = keystoreProperties['storePassword'] 40 | releaseKeyAlias = keystoreProperties['keyAlias'] 41 | releaseKeyPassword = keystoreProperties['keyPassword'] 42 | 43 | version_kotlin = '1.3.0' 44 | version_lifecycle = '2.0.0' 45 | version_coroutines = '1.0.1' 46 | version_room = "2.1.0-alpha03" 47 | version_nav = "1.0.0-alpha07" 48 | version_support = "1.0.0" 49 | version_espresso = "3.1.0-alpha4" 50 | version_runner = "1.1.0-alpha4" 51 | version_rules = "1.1.0-alpha4" 52 | version_arch_core = "2.0.0" 53 | } 54 | 55 | repositories { 56 | google() 57 | jcenter() 58 | } 59 | dependencies { 60 | classpath 'com.android.tools.build:gradle:3.2.1' 61 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$version_kotlin" 62 | } 63 | } 64 | 65 | allprojects { 66 | repositories { 67 | google() 68 | jcenter() 69 | } 70 | } 71 | 72 | task clean(type: Delete) { 73 | delete rootProject.buildDir 74 | } 75 | -------------------------------------------------------------------------------- /codelab-00/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | 17 | # You can specify the keystore properties file from the command line. 18 | # Example release build using release keystore 'release-keystore.properties': 19 | # ./gradlew -PkeystorePropertiesFilename=release-keystore.properties assembleRelease 20 | # 21 | # Default source: keystore.properties 22 | # 23 | keystorePropertiesFilename=keystore.properties 24 | 25 | -------------------------------------------------------------------------------- /codelab-00/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /codelab-00/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /codelab-00/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /codelab-00/keystore.properties: -------------------------------------------------------------------------------- 1 | storeFile=kotlin_td_keystore.jks 2 | storePassword=B!llingS@mpl3 3 | keyAlias=IAB 4 | keyPassword=B!llingS@mpl3 5 | -------------------------------------------------------------------------------- /codelab-00/kotlin_td_keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-00/kotlin_td_keystore.jks -------------------------------------------------------------------------------- /codelab-00/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /codelab-01/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.idea/caches/build_file_checksums.ser 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | /app/release -------------------------------------------------------------------------------- /codelab-01/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /codelab-01/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | import android.os.Bundle 19 | import androidx.appcompat.app.AppCompatActivity 20 | 21 | class MainActivity : AppCompatActivity() { 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_main) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MakePurchaseFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | 19 | import android.os.Bundle 20 | import android.util.Log 21 | import android.view.LayoutInflater 22 | import android.view.View 23 | import android.view.ViewGroup 24 | import androidx.fragment.app.Fragment 25 | import androidx.recyclerview.widget.RecyclerView 26 | 27 | /** 28 | * This Fragment is simply a wrapper for the inventory (i.e. items for sale). It contains two 29 | * [lists][RecyclerView], one for subscriptions and one for in-app products. Here again there is 30 | * no complicated billing logic. All the billing logic reside inside the [BillingRepository]. 31 | * The [BillingRepository] provides a [AugmentedSkuDetails] object that shows what 32 | * is for sale and whether the user is allowed to buy the item at this moment. E.g. if the user 33 | * already has a full tank of gas, then they cannot buy gas at this moment. 34 | */ 35 | class MakePurchaseFragment : Fragment() { 36 | 37 | val LOG_TAG = "MakePurchaseFragment" 38 | 39 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 40 | return inflater.inflate(R.layout.fragment_make_purchase, container, false) 41 | } 42 | 43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 44 | super.onViewCreated(view, savedInstanceState) 45 | Log.d(LOG_TAG, "onViewCreated") 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/BillingRepository.kt: -------------------------------------------------------------------------------- 1 | package com.example.playbilling.trivialdrive.kotlin.billingrepo 2 | 3 | /** 4 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | class BillingRepository { 19 | 20 | } -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetails.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.Entity 19 | import androidx.room.PrimaryKey 20 | 21 | @Entity 22 | data class AugmentedSkuDetails(val canPurchase: Boolean, /* Not in SkuDetails; it's the augmentation */ 23 | @PrimaryKey val sku: String, 24 | val type: String?, 25 | val price: String?, 26 | val title: String?, 27 | val description: String?, 28 | val originalJson: String?) -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetailsDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.lifecycle.LiveData 19 | import androidx.room.Dao 20 | import androidx.room.Insert 21 | import androidx.room.OnConflictStrategy 22 | import androidx.room.Query 23 | import androidx.room.Transaction 24 | import com.android.billingclient.api.BillingClient 25 | import com.android.billingclient.api.SkuDetails 26 | 27 | @Dao 28 | interface AugmentedSkuDetailsDao { 29 | 30 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.SUBS}'") 31 | fun getSubscriptionSkuDetails(): LiveData> 32 | 33 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.INAPP}'") 34 | fun getInappSkuDetails(): LiveData> 35 | 36 | @Transaction 37 | fun insertOrUpdate(skuDetails: SkuDetails) = skuDetails.apply { 38 | val result = getById(sku) 39 | val canPurchase = if (result == null) true else result.canPurchase 40 | val originalJson = toString().substring("SkuDetails: ".length) 41 | val skuDetails = AugmentedSkuDetails(canPurchase, sku, type, price, title, description, originalJson) 42 | insert(skuDetails) 43 | } 44 | 45 | @Transaction 46 | fun insertOrUpdate(sku: String, canPurchase: Boolean) { 47 | val result = getById(sku) 48 | if (result != null) { 49 | update(sku, canPurchase) 50 | } else { 51 | insert(AugmentedSkuDetails(canPurchase, sku, null, null, null, null, null)) 52 | } 53 | } 54 | 55 | @Query("SELECT * FROM AugmentedSkuDetails WHERE sku = :sku") 56 | fun getById(sku: String): AugmentedSkuDetails 57 | 58 | @Insert(onConflict = OnConflictStrategy.REPLACE) 59 | fun insert(augmentedSkuDetails: AugmentedSkuDetails) 60 | 61 | @Query("UPDATE AugmentedSkuDetails SET canPurchase = :canPurchase WHERE sku = :sku") 62 | fun update(sku: String, canPurchase: Boolean) 63 | } -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/CachedPurchase.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.Entity 19 | import androidx.room.Ignore 20 | import androidx.room.PrimaryKey 21 | import androidx.room.TypeConverter 22 | import androidx.room.TypeConverters 23 | import com.android.billingclient.api.Purchase 24 | 25 | @Entity(tableName = "purchase_table") 26 | @TypeConverters(PurchaseTypeConverter::class) 27 | class CachedPurchase(val data: Purchase) { 28 | 29 | @PrimaryKey(autoGenerate = true) 30 | var id: Int = 0 31 | 32 | @Ignore 33 | val purchaseToken = data.purchaseToken 34 | @Ignore 35 | val sku = data.sku 36 | 37 | override fun equals(other: Any?): Boolean { 38 | return when (other) { 39 | is CachedPurchase -> data.equals(other.data) 40 | is Purchase -> data.equals(other) 41 | else -> false 42 | } 43 | } 44 | 45 | override fun hashCode(): Int { 46 | return data.hashCode() 47 | } 48 | 49 | } 50 | 51 | class PurchaseTypeConverter { 52 | @TypeConverter 53 | fun toString(purchase: Purchase): String = purchase.originalJson + '|' + purchase.signature 54 | 55 | @TypeConverter 56 | fun toPurchase(data: String): Purchase = data.split('|').let { 57 | Purchase(it[0], it[1]) 58 | } 59 | } -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/Entitlements.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 18 | 19 | import androidx.room.Entity 20 | import androidx.room.PrimaryKey 21 | 22 | private const val FULL_TANK = 4 23 | private const val EMPTY_TANK = 0 24 | const val GAS_PURCHASE = 1 25 | 26 | abstract class Entitlement { 27 | @PrimaryKey 28 | var id: Int = 1 29 | 30 | abstract fun mayPurchase(): Boolean 31 | } 32 | 33 | @Entity(tableName = "premium_car") 34 | data class PremiumCar(val entitled: Boolean) : Entitlement() { 35 | override fun mayPurchase(): Boolean = !entitled 36 | } 37 | 38 | @Entity(tableName = "gold_status") 39 | data class GoldStatus(val entitled: Boolean) : Entitlement() { 40 | override fun mayPurchase(): Boolean = !entitled 41 | } 42 | 43 | @Entity(tableName = "gas_tank") 44 | class GasTank(private var level: Int) : Entitlement() { 45 | 46 | fun getLevel() = level 47 | 48 | override fun mayPurchase(): Boolean = level < FULL_TANK 49 | 50 | fun needGas(): Boolean = level <= EMPTY_TANK 51 | 52 | fun decrement(by: Int = 1) { 53 | level -= by 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/LocalBillingDb.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | 19 | import android.content.Context 20 | import androidx.room.Database 21 | import androidx.room.Room 22 | import androidx.room.RoomDatabase 23 | 24 | @Database(entities = [CachedPurchase::class, GasTank::class, PremiumCar::class, GoldStatus::class, AugmentedSkuDetails::class], 25 | version = 1, exportSchema = false) 26 | abstract class LocalBillingDb : RoomDatabase() { 27 | abstract fun purchaseDao(): PurchaseDao 28 | abstract fun entitlementsDao(): EntitlementsDao 29 | abstract fun skuDetailsDao(): AugmentedSkuDetailsDao 30 | 31 | companion object { 32 | @Volatile 33 | private var INSTANCE: LocalBillingDb? = null 34 | 35 | fun getInstance(context: Context): LocalBillingDb { 36 | return INSTANCE 37 | ?: synchronized(this) { 38 | var instance = INSTANCE 39 | if (instance == null) { 40 | instance = Room.databaseBuilder( 41 | context.applicationContext, 42 | LocalBillingDb::class.java, 43 | "purchase_db") 44 | .fallbackToDestructiveMigration()//remote sources more reliable 45 | .build() 46 | INSTANCE = instance 47 | } 48 | instance!! 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/PurchaseDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.Dao 19 | import androidx.room.Delete 20 | import androidx.room.Insert 21 | import androidx.room.Query 22 | import androidx.room.Transaction 23 | import com.android.billingclient.api.Purchase 24 | 25 | @Dao 26 | interface PurchaseDao { 27 | @Query("SELECT * FROM purchase_table") 28 | fun getPurchases(): List 29 | 30 | @Insert 31 | fun insert(purchase: CachedPurchase) 32 | 33 | @Transaction 34 | fun insert(vararg purchases: Purchase) { 35 | purchases.forEach { 36 | insert(CachedPurchase(data = it)) 37 | } 38 | } 39 | 40 | @Delete 41 | fun delete(vararg purchases: CachedPurchase) 42 | 43 | @Query("DELETE FROM purchase_table") 44 | fun deleteAll() 45 | } -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/free_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/free_car.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gas.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gas_level_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gas_level_0.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gas_level_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gas_level_1.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gas_level_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gas_level_2.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gas_level_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gas_level_3.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gas_level_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gas_level_4.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gold_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gold_status.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/gold_subs_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/gold_subs_icon.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/premium_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/premium_car.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/drawable-v24/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/drawable-v24/title.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/layout/fragment_make_purchase.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 29 | 35 | 38 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/navigation/navigation_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | 25 | 30 | 33 | 34 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | #008577 21 | #00574B 22 | #FFCA28 23 | #FFE082 24 | #FFECB3 25 | #CFD8DC 26 | #90A4AE 27 | #263238 28 | 29 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 16dp 21 | 8dp 22 | 32dp 23 | 8dp 24 | 8dp 25 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Trivial Drive Kotlin 19 | Hello blank fragment 20 | Fun Products 21 | Fun Subscriptions 22 | Vroooom, you drove a few miles! 23 | Oh, no! You are out of gas! Try buying some! 24 | 25 | -------------------------------------------------------------------------------- /codelab-01/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-01/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | 17 | # You can specify the keystore properties file from the command line. 18 | # Example release build using release keystore 'release-keystore.properties': 19 | # ./gradlew -PkeystorePropertiesFilename=release-keystore.properties assembleRelease 20 | # 21 | # Default source: keystore.properties 22 | # 23 | keystorePropertiesFilename=keystore.properties 24 | 25 | -------------------------------------------------------------------------------- /codelab-01/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /codelab-01/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /codelab-01/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /codelab-01/keystore.properties: -------------------------------------------------------------------------------- 1 | storeFile=kotlin_td_keystore.jks 2 | storePassword=B!llingS@mpl3 3 | keyAlias=IAB 4 | keyPassword=B!llingS@mpl3 5 | -------------------------------------------------------------------------------- /codelab-01/kotlin_td_keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-01/kotlin_td_keystore.jks -------------------------------------------------------------------------------- /codelab-01/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /codelab-02/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.idea/caches/build_file_checksums.ser 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | /app/release -------------------------------------------------------------------------------- /codelab-02/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /codelab-02/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | import android.os.Bundle 19 | import androidx.appcompat.app.AppCompatActivity 20 | 21 | class MainActivity : AppCompatActivity() { 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_main) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MakePurchaseFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | 19 | import android.os.Bundle 20 | import android.util.Log 21 | import android.view.LayoutInflater 22 | import android.view.View 23 | import android.view.ViewGroup 24 | import androidx.fragment.app.Fragment 25 | import androidx.recyclerview.widget.RecyclerView 26 | 27 | /** 28 | * This Fragment is simply a wrapper for the inventory (i.e. items for sale). It contains two 29 | * [lists][RecyclerView], one for subscriptions and one for in-app products. Here again there is 30 | * no complicated billing logic. All the billing logic reside inside the [BillingRepository]. 31 | * The [BillingRepository] provides a [AugmentedSkuDetails] object that shows what 32 | * is for sale and whether the user is allowed to buy the item at this moment. E.g. if the user 33 | * already has a full tank of gas, then they cannot buy gas at this moment. 34 | */ 35 | class MakePurchaseFragment : Fragment() { 36 | 37 | val LOG_TAG = "MakePurchaseFragment" 38 | 39 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 40 | return inflater.inflate(R.layout.fragment_make_purchase, container, false) 41 | } 42 | 43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 44 | super.onViewCreated(view, savedInstanceState) 45 | Log.d(LOG_TAG, "onViewCreated") 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/BillingWebservice.kt: -------------------------------------------------------------------------------- 1 | package com.example.playbilling.trivialdrive.kotlin.billingrepo 2 | 3 | import com.android.billingclient.api.Purchase 4 | 5 | /** 6 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | 21 | class BillingWebservice { 22 | fun getPurchases(): Any { 23 | return Any()//TODO("not implemented") 24 | } 25 | fun updateServer(purchases: Set) { 26 | //TODO("not implemented") 27 | } 28 | fun onComsumeResponse(purchaseToken: String?, responseCode: Int) { 29 | //TODO("not implemented") 30 | } 31 | companion object { 32 | fun create(): BillingWebservice { 33 | //TODO("not implemented") 34 | return BillingWebservice() 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetails.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.Entity 19 | import androidx.room.PrimaryKey 20 | 21 | @Entity 22 | data class AugmentedSkuDetails(val canPurchase: Boolean, /* Not in SkuDetails; it's the augmentation */ 23 | @PrimaryKey val sku: String, 24 | val type: String?, 25 | val price: String?, 26 | val title: String?, 27 | val description: String?, 28 | val originalJson: String?) -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetailsDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.lifecycle.LiveData 19 | import androidx.room.* 20 | import com.android.billingclient.api.BillingClient 21 | import com.android.billingclient.api.SkuDetails 22 | 23 | @Dao 24 | interface AugmentedSkuDetailsDao { 25 | 26 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.SUBS}'") 27 | fun getSubscriptionSkuDetails(): LiveData> 28 | 29 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.INAPP}'") 30 | fun getInappSkuDetails(): LiveData> 31 | 32 | @Transaction 33 | fun insertOrUpdate(skuDetails: SkuDetails) = skuDetails.apply { 34 | val result = getById(sku) 35 | val bool = if (result == null) true else result.canPurchase 36 | val originalJson = toString().substring("SkuDetails: ".length) 37 | val skuDetails = AugmentedSkuDetails(bool, sku, type, price, title, description, originalJson) 38 | insert(skuDetails) 39 | } 40 | 41 | @Transaction 42 | fun insertOrUpdate(sku: String, canPurchase: Boolean) { 43 | val result = getById(sku) 44 | if (result != null) { 45 | update(sku, canPurchase) 46 | } else { 47 | insert(AugmentedSkuDetails(canPurchase, sku, null, null, null, null, null)) 48 | } 49 | } 50 | 51 | @Query("SELECT * FROM AugmentedSkuDetails WHERE sku = :sku") 52 | fun getById(sku: String): AugmentedSkuDetails 53 | 54 | @Insert(onConflict = OnConflictStrategy.REPLACE) 55 | fun insert(augmentedSkuDetails: AugmentedSkuDetails) 56 | 57 | @Query("UPDATE AugmentedSkuDetails SET canPurchase = :canPurchase WHERE sku = :sku") 58 | fun update(sku: String, canPurchase: Boolean) 59 | } -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/CachedPurchase.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.* 19 | import com.android.billingclient.api.Purchase 20 | 21 | @Entity(tableName = "purchase_table") 22 | @TypeConverters(PurchaseTypeConverter::class) 23 | class CachedPurchase(val data: Purchase) { 24 | 25 | @PrimaryKey(autoGenerate = true) 26 | var id: Int = 0 27 | 28 | @Ignore 29 | val purchaseToken = data.purchaseToken 30 | @Ignore 31 | val sku = data.sku 32 | 33 | override fun equals(other: Any?): Boolean { 34 | return when (other) { 35 | is CachedPurchase -> data.equals(other.data) 36 | is Purchase -> data.equals(other) 37 | else -> false 38 | } 39 | } 40 | 41 | override fun hashCode(): Int { 42 | return data.hashCode() 43 | } 44 | 45 | } 46 | 47 | class PurchaseTypeConverter { 48 | @TypeConverter 49 | fun toString(purchase: Purchase): String = purchase.originalJson + '|' + purchase.signature 50 | 51 | @TypeConverter 52 | fun toPurchase(data: String): Purchase = data.split('|').let { 53 | Purchase(it[0], it[1]) 54 | } 55 | } -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/Entitlements.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 18 | 19 | import androidx.room.Entity 20 | import androidx.room.PrimaryKey 21 | 22 | private const val FULL_TANK = 4 23 | private const val EMPTY_TANK = 0 24 | const val GAS_PURCHASE = 1 25 | 26 | abstract class Entitlement { 27 | @PrimaryKey 28 | var id: Int = 1 29 | 30 | abstract fun mayPurchase(): Boolean 31 | } 32 | 33 | @Entity(tableName = "premium_car") 34 | data class PremiumCar(val entitled: Boolean) : Entitlement() { 35 | override fun mayPurchase(): Boolean = !entitled 36 | } 37 | 38 | @Entity(tableName = "gold_status") 39 | data class GoldStatus(val entitled: Boolean) : Entitlement() { 40 | override fun mayPurchase(): Boolean = !entitled 41 | } 42 | 43 | @Entity(tableName = "gas_tank") 44 | class GasTank(private var level: Int) : Entitlement() { 45 | 46 | fun getLevel() = level 47 | 48 | override fun mayPurchase(): Boolean = level < FULL_TANK 49 | 50 | fun needGas(): Boolean = level <= EMPTY_TANK 51 | 52 | fun decrement(by: Int = 1) { 53 | level -= by 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/LocalBillingDb.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | 19 | import android.content.Context 20 | import androidx.room.Database 21 | import androidx.room.Room 22 | import androidx.room.RoomDatabase 23 | 24 | @Database(entities = [CachedPurchase::class, GasTank::class, PremiumCar::class, GoldStatus::class, AugmentedSkuDetails::class], 25 | version = 1, exportSchema = false) 26 | abstract class LocalBillingDb : RoomDatabase() { 27 | abstract fun purchaseDao(): PurchaseDao 28 | abstract fun entitlementsDao(): EntitlementsDao 29 | abstract fun skuDetailsDao(): AugmentedSkuDetailsDao 30 | 31 | companion object { 32 | @Volatile 33 | private var INSTANCE: LocalBillingDb? = null 34 | 35 | fun getInstance(context: Context): LocalBillingDb { 36 | return INSTANCE 37 | ?: synchronized(this) { 38 | var instance = INSTANCE 39 | if (instance == null) { 40 | instance = Room.databaseBuilder( 41 | context.applicationContext, 42 | LocalBillingDb::class.java, 43 | "purchase_db") 44 | .fallbackToDestructiveMigration()//remote sources more reliable 45 | .build() 46 | INSTANCE = instance 47 | } 48 | instance!! 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/PurchaseDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.* 19 | import com.android.billingclient.api.Purchase 20 | 21 | @Dao 22 | interface PurchaseDao { 23 | @Query("SELECT * FROM purchase_table") 24 | fun getPurchases(): List 25 | 26 | @Insert 27 | fun insert(purchase: CachedPurchase) 28 | 29 | @Transaction 30 | fun insert(vararg purchases: Purchase) { 31 | purchases.forEach { 32 | insert(CachedPurchase(data = it)) 33 | } 34 | } 35 | 36 | @Delete 37 | fun delete(vararg purchases: CachedPurchase) 38 | 39 | @Query("DELETE FROM purchase_table") 40 | fun deleteAll() 41 | } -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/free_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/free_car.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gas.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gas_level_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gas_level_0.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gas_level_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gas_level_1.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gas_level_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gas_level_2.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gas_level_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gas_level_3.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gas_level_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gas_level_4.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gold_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gold_status.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/gold_subs_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/gold_subs_icon.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/premium_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/premium_car.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/drawable-v24/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/drawable-v24/title.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/layout/fragment_make_purchase.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 29 | 35 | 38 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/navigation/navigation_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | 25 | 30 | 33 | 34 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | #008577 21 | #00574B 22 | #FFCA28 23 | #FFE082 24 | #FFECB3 25 | #CFD8DC 26 | #90A4AE 27 | #263238 28 | 29 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 16dp 21 | 8dp 22 | 32dp 23 | 8dp 24 | 8dp 25 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Trivial Drive Kotlin 19 | Hello blank fragment 20 | Fun Products 21 | Fun Subscriptions 22 | Vroooom, you drove a few miles! 23 | Oh, no! You are out of gas! Try buying some! 24 | 25 | -------------------------------------------------------------------------------- /codelab-02/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-02/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | 17 | # You can specify the keystore properties file from the command line. 18 | # Example release build using release keystore 'release-keystore.properties': 19 | # ./gradlew -PkeystorePropertiesFilename=release-keystore.properties assembleRelease 20 | # 21 | # Default source: keystore.properties 22 | # 23 | keystorePropertiesFilename=keystore.properties 24 | 25 | -------------------------------------------------------------------------------- /codelab-02/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /codelab-02/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /codelab-02/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /codelab-02/keystore.properties: -------------------------------------------------------------------------------- 1 | storeFile=kotlin_td_keystore.jks 2 | storePassword=B!llingS@mpl3 3 | keyAlias=IAB 4 | keyPassword=B!llingS@mpl3 5 | -------------------------------------------------------------------------------- /codelab-02/kotlin_td_keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-02/kotlin_td_keystore.jks -------------------------------------------------------------------------------- /codelab-02/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /codelab-03/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.idea/caches/build_file_checksums.ser 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | /app/release -------------------------------------------------------------------------------- /codelab-03/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /codelab-03/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | import android.os.Bundle 19 | import androidx.appcompat.app.AppCompatActivity 20 | 21 | class MainActivity : AppCompatActivity() { 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_main) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MakePurchaseFragment.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | 19 | import android.os.Bundle 20 | import android.util.Log 21 | import android.view.LayoutInflater 22 | import android.view.View 23 | import android.view.ViewGroup 24 | import androidx.fragment.app.Fragment 25 | import androidx.recyclerview.widget.RecyclerView 26 | 27 | /** 28 | * This Fragment is simply a wrapper for the inventory (i.e. items for sale). It contains two 29 | * [lists][RecyclerView], one for subscriptions and one for in-app products. Here again there is 30 | * no complicated billing logic. All the billing logic reside inside the [BillingRepository]. 31 | * The [BillingRepository] provides a [AugmentedSkuDetails] object that shows what 32 | * is for sale and whether the user is allowed to buy the item at this moment. E.g. if the user 33 | * already has a full tank of gas, then they cannot buy gas at this moment. 34 | */ 35 | class MakePurchaseFragment : Fragment() { 36 | 37 | val LOG_TAG = "MakePurchaseFragment" 38 | 39 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { 40 | return inflater.inflate(R.layout.fragment_make_purchase, container, false) 41 | } 42 | 43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 44 | super.onViewCreated(view, savedInstanceState) 45 | Log.d(LOG_TAG, "onViewCreated") 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/BillingWebservice.kt: -------------------------------------------------------------------------------- 1 | package com.example.playbilling.trivialdrive.kotlin.billingrepo 2 | 3 | import com.android.billingclient.api.Purchase 4 | 5 | /** 6 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | 21 | class BillingWebservice { 22 | fun getPurchases(): Any { 23 | return Any()//TODO("not implemented") 24 | } 25 | fun updateServer(purchases: Set) { 26 | //TODO("not implemented") 27 | } 28 | fun onComsumeResponse(purchaseToken: String?, responseCode: Int) { 29 | //TODO("not implemented") 30 | } 31 | companion object { 32 | fun create(): BillingWebservice { 33 | //TODO("not implemented") 34 | return BillingWebservice() 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetails.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.Entity 19 | import androidx.room.PrimaryKey 20 | 21 | @Entity 22 | data class AugmentedSkuDetails(val canPurchase: Boolean, /* Not in SkuDetails; it's the augmentation */ 23 | @PrimaryKey val sku: String, 24 | val type: String?, 25 | val price: String?, 26 | val title: String?, 27 | val description: String?, 28 | val originalJson: String?) -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetailsDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.lifecycle.LiveData 19 | import androidx.room.* 20 | import com.android.billingclient.api.BillingClient 21 | import com.android.billingclient.api.SkuDetails 22 | 23 | @Dao 24 | interface AugmentedSkuDetailsDao { 25 | 26 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.SUBS}'") 27 | fun getSubscriptionSkuDetails(): LiveData> 28 | 29 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.INAPP}'") 30 | fun getInappSkuDetails(): LiveData> 31 | 32 | @Transaction 33 | fun insertOrUpdate(skuDetails: SkuDetails) = skuDetails.apply { 34 | val result = getById(sku) 35 | val bool = if (result == null) true else result.canPurchase 36 | val originalJson = toString().substring("SkuDetails: ".length) 37 | val skuDetails = AugmentedSkuDetails(bool, sku, type, price, title, description, originalJson) 38 | insert(skuDetails) 39 | } 40 | 41 | @Transaction 42 | fun insertOrUpdate(sku: String, canPurchase: Boolean) { 43 | val result = getById(sku) 44 | if (result != null) { 45 | update(sku, canPurchase) 46 | } else { 47 | insert(AugmentedSkuDetails(canPurchase, sku, null, null, null, null, null)) 48 | } 49 | } 50 | 51 | @Query("SELECT * FROM AugmentedSkuDetails WHERE sku = :sku") 52 | fun getById(sku: String): AugmentedSkuDetails 53 | 54 | @Insert(onConflict = OnConflictStrategy.REPLACE) 55 | fun insert(augmentedSkuDetails: AugmentedSkuDetails) 56 | 57 | @Query("UPDATE AugmentedSkuDetails SET canPurchase = :canPurchase WHERE sku = :sku") 58 | fun update(sku: String, canPurchase: Boolean) 59 | } -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/CachedPurchase.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.* 19 | import com.android.billingclient.api.Purchase 20 | 21 | @Entity(tableName = "purchase_table") 22 | @TypeConverters(PurchaseTypeConverter::class) 23 | class CachedPurchase(val data: Purchase) { 24 | 25 | @PrimaryKey(autoGenerate = true) 26 | var id: Int = 0 27 | 28 | @Ignore 29 | val purchaseToken = data.purchaseToken 30 | @Ignore 31 | val sku = data.sku 32 | 33 | override fun equals(other: Any?): Boolean { 34 | return when (other) { 35 | is CachedPurchase -> data.equals(other.data) 36 | is Purchase -> data.equals(other) 37 | else -> false 38 | } 39 | } 40 | 41 | override fun hashCode(): Int { 42 | return data.hashCode() 43 | } 44 | 45 | } 46 | 47 | class PurchaseTypeConverter { 48 | @TypeConverter 49 | fun toString(purchase: Purchase): String = purchase.originalJson + '|' + purchase.signature 50 | 51 | @TypeConverter 52 | fun toPurchase(data: String): Purchase = data.split('|').let { 53 | Purchase(it[0], it[1]) 54 | } 55 | } -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/Entitlements.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 18 | 19 | import androidx.room.Entity 20 | import androidx.room.PrimaryKey 21 | 22 | private const val FULL_TANK = 4 23 | private const val EMPTY_TANK = 0 24 | const val GAS_PURCHASE = 1 25 | 26 | abstract class Entitlement { 27 | @PrimaryKey 28 | var id: Int = 1 29 | 30 | abstract fun mayPurchase(): Boolean 31 | } 32 | 33 | @Entity(tableName = "premium_car") 34 | data class PremiumCar(val entitled: Boolean) : Entitlement() { 35 | override fun mayPurchase(): Boolean = !entitled 36 | } 37 | 38 | @Entity(tableName = "gold_status") 39 | data class GoldStatus(val entitled: Boolean) : Entitlement() { 40 | override fun mayPurchase(): Boolean = !entitled 41 | } 42 | 43 | @Entity(tableName = "gas_tank") 44 | class GasTank(private var level: Int) : Entitlement() { 45 | 46 | fun getLevel() = level 47 | 48 | override fun mayPurchase(): Boolean = level < FULL_TANK 49 | 50 | fun needGas(): Boolean = level <= EMPTY_TANK 51 | 52 | fun decrement(by: Int = 1) { 53 | level -= by 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/LocalBillingDb.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | 19 | import android.content.Context 20 | import androidx.room.Database 21 | import androidx.room.Room 22 | import androidx.room.RoomDatabase 23 | 24 | @Database(entities = [CachedPurchase::class, GasTank::class, PremiumCar::class, GoldStatus::class, AugmentedSkuDetails::class], 25 | version = 1, exportSchema = false) 26 | abstract class LocalBillingDb : RoomDatabase() { 27 | abstract fun purchaseDao(): PurchaseDao 28 | abstract fun entitlementsDao(): EntitlementsDao 29 | abstract fun skuDetailsDao(): AugmentedSkuDetailsDao 30 | 31 | companion object { 32 | @Volatile 33 | private var INSTANCE: LocalBillingDb? = null 34 | 35 | fun getInstance(context: Context): LocalBillingDb = INSTANCE ?: synchronized(this) { 36 | INSTANCE ?: Room.databaseBuilder( 37 | context.applicationContext, 38 | LocalBillingDb::class.java, 39 | "purchase_db") 40 | .fallbackToDestructiveMigration() 41 | .build().also { INSTANCE = it } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/PurchaseDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.* 19 | import com.android.billingclient.api.Purchase 20 | 21 | @Dao 22 | interface PurchaseDao { 23 | @Query("SELECT * FROM purchase_table") 24 | fun getPurchases(): List 25 | 26 | @Insert 27 | fun insert(purchase: CachedPurchase) 28 | 29 | @Transaction 30 | fun insert(vararg purchases: Purchase) { 31 | purchases.forEach { 32 | insert(CachedPurchase(data = it)) 33 | } 34 | } 35 | 36 | @Delete 37 | fun delete(vararg purchases: CachedPurchase) 38 | 39 | @Query("DELETE FROM purchase_table") 40 | fun deleteAll() 41 | } -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/free_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/free_car.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gas.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gas_level_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gas_level_0.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gas_level_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gas_level_1.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gas_level_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gas_level_2.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gas_level_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gas_level_3.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gas_level_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gas_level_4.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gold_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gold_status.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/gold_subs_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/gold_subs_icon.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/premium_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/premium_car.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/drawable-v24/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/drawable-v24/title.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/layout/fragment_make_purchase.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 29 | 35 | 38 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/navigation/navigation_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | 25 | 30 | 33 | 34 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | #008577 21 | #00574B 22 | #FFCA28 23 | #FFE082 24 | #FFECB3 25 | #CFD8DC 26 | #90A4AE 27 | #263238 28 | 29 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 16dp 21 | 8dp 22 | 32dp 23 | 8dp 24 | 8dp 25 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Trivial Drive Kotlin 19 | Hello blank fragment 20 | Fun Products 21 | Fun Subscriptions 22 | Vroooom, you drove a few miles! 23 | Oh, no! You are out of gas! Try buying some! 24 | 25 | -------------------------------------------------------------------------------- /codelab-03/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-03/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | 17 | # You can specify the keystore properties file from the command line. 18 | # Example release build using release keystore 'release-keystore.properties': 19 | # ./gradlew -PkeystorePropertiesFilename=release-keystore.properties assembleRelease 20 | # 21 | # Default source: keystore.properties 22 | # 23 | keystorePropertiesFilename=keystore.properties 24 | 25 | -------------------------------------------------------------------------------- /codelab-03/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /codelab-03/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /codelab-03/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /codelab-03/keystore.properties: -------------------------------------------------------------------------------- 1 | storeFile=kotlin_td_keystore.jks 2 | storePassword=B!llingS@mpl3 3 | keyAlias=IAB 4 | keyPassword=B!llingS@mpl3 5 | -------------------------------------------------------------------------------- /codelab-03/kotlin_td_keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-03/kotlin_td_keystore.jks -------------------------------------------------------------------------------- /codelab-03/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /codelab-04/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | /.idea/caches/build_file_checksums.ser 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | .DS_Store 10 | /build 11 | /captures 12 | .externalNativeBuild 13 | /app/release -------------------------------------------------------------------------------- /codelab-04/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /codelab-04/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/MainActivity.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin 17 | 18 | import android.os.Bundle 19 | import androidx.appcompat.app.AppCompatActivity 20 | 21 | class MainActivity : AppCompatActivity() { 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_main) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/BillingWebservice.kt: -------------------------------------------------------------------------------- 1 | package com.example.playbilling.trivialdrive.kotlin.billingrepo 2 | 3 | import com.android.billingclient.api.Purchase 4 | 5 | /** 6 | * Copyright (C) 2019 Google Inc. All Rights Reserved. 7 | * 8 | * Licensed under the Apache License, Version 2.0 (the "License"); 9 | * you may not use this file except in compliance with the License. 10 | * You may obtain a copy of the License at 11 | * 12 | * http://www.apache.org/licenses/LICENSE-2.0 13 | * 14 | * Unless required by applicable law or agreed to in writing, software 15 | * distributed under the License is distributed on an "AS IS" BASIS, 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | * See the License for the specific language governing permissions and 18 | * limitations under the License. 19 | */ 20 | 21 | class BillingWebservice { 22 | fun getPurchases(): Any { 23 | return Any()//TODO("not implemented") 24 | } 25 | fun updateServer(purchases: Set) { 26 | //TODO("not implemented") 27 | } 28 | fun onComsumeResponse(purchaseToken: String?, responseCode: Int) { 29 | //TODO("not implemented") 30 | } 31 | companion object { 32 | fun create(): BillingWebservice { 33 | //TODO("not implemented") 34 | return BillingWebservice() 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetails.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.Entity 19 | import androidx.room.PrimaryKey 20 | 21 | @Entity 22 | data class AugmentedSkuDetails(val canPurchase: Boolean, /* Not in SkuDetails; it's the augmentation */ 23 | @PrimaryKey val sku: String, 24 | val type: String?, 25 | val price: String?, 26 | val title: String?, 27 | val description: String?, 28 | val originalJson: String?) -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/AugmentedSkuDetailsDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.lifecycle.LiveData 19 | import androidx.room.* 20 | import com.android.billingclient.api.BillingClient 21 | import com.android.billingclient.api.SkuDetails 22 | 23 | @Dao 24 | interface AugmentedSkuDetailsDao { 25 | 26 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.SUBS}'") 27 | fun getSubscriptionSkuDetails(): LiveData> 28 | 29 | @Query("SELECT * FROM AugmentedSkuDetails WHERE type = '${BillingClient.SkuType.INAPP}'") 30 | fun getInappSkuDetails(): LiveData> 31 | 32 | @Transaction 33 | fun insertOrUpdate(skuDetails: SkuDetails) = skuDetails.apply { 34 | val result = getById(sku) 35 | val bool = if (result == null) true else result.canPurchase 36 | val originalJson = toString().substring("SkuDetails: ".length) 37 | val skuDetails = AugmentedSkuDetails(bool, sku, type, price, title, description, originalJson) 38 | insert(skuDetails) 39 | } 40 | 41 | @Transaction 42 | fun insertOrUpdate(sku: String, canPurchase: Boolean) { 43 | val result = getById(sku) 44 | if (result != null) { 45 | update(sku, canPurchase) 46 | } else { 47 | insert(AugmentedSkuDetails(canPurchase, sku, null, null, null, null, null)) 48 | } 49 | } 50 | 51 | @Query("SELECT * FROM AugmentedSkuDetails WHERE sku = :sku") 52 | fun getById(sku: String): AugmentedSkuDetails 53 | 54 | @Insert(onConflict = OnConflictStrategy.REPLACE) 55 | fun insert(augmentedSkuDetails: AugmentedSkuDetails) 56 | 57 | @Query("UPDATE AugmentedSkuDetails SET canPurchase = :canPurchase WHERE sku = :sku") 58 | fun update(sku: String, canPurchase: Boolean) 59 | } -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/CachedPurchase.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.* 19 | import com.android.billingclient.api.Purchase 20 | 21 | @Entity(tableName = "purchase_table") 22 | @TypeConverters(PurchaseTypeConverter::class) 23 | class CachedPurchase(val data: Purchase) { 24 | 25 | @PrimaryKey(autoGenerate = true) 26 | var id: Int = 0 27 | 28 | @Ignore 29 | val purchaseToken = data.purchaseToken 30 | @Ignore 31 | val sku = data.sku 32 | 33 | override fun equals(other: Any?): Boolean { 34 | return when (other) { 35 | is CachedPurchase -> data.equals(other.data) 36 | is Purchase -> data.equals(other) 37 | else -> false 38 | } 39 | } 40 | 41 | override fun hashCode(): Int { 42 | return data.hashCode() 43 | } 44 | 45 | } 46 | 47 | class PurchaseTypeConverter { 48 | @TypeConverter 49 | fun toString(purchase: Purchase): String = purchase.originalJson + '|' + purchase.signature 50 | 51 | @TypeConverter 52 | fun toPurchase(data: String): Purchase = data.split('|').let { 53 | Purchase(it[0], it[1]) 54 | } 55 | } -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/Entitlements.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 18 | 19 | import androidx.room.Entity 20 | import androidx.room.PrimaryKey 21 | 22 | private const val FULL_TANK = 4 23 | private const val EMPTY_TANK = 0 24 | const val GAS_PURCHASE = 1 25 | 26 | abstract class Entitlement { 27 | @PrimaryKey 28 | var id: Int = 1 29 | 30 | abstract fun mayPurchase(): Boolean 31 | } 32 | 33 | @Entity(tableName = "premium_car") 34 | data class PremiumCar(val entitled: Boolean) : Entitlement() { 35 | override fun mayPurchase(): Boolean = !entitled 36 | } 37 | 38 | @Entity(tableName = "gold_status") 39 | data class GoldStatus(val entitled: Boolean) : Entitlement() { 40 | override fun mayPurchase(): Boolean = !entitled 41 | } 42 | 43 | @Entity(tableName = "gas_tank") 44 | class GasTank(private var level: Int) : Entitlement() { 45 | 46 | fun getLevel() = level 47 | 48 | override fun mayPurchase(): Boolean = level < FULL_TANK 49 | 50 | fun needGas(): Boolean = level <= EMPTY_TANK 51 | 52 | fun decrement(by: Int = 1) { 53 | level -= by 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/LocalBillingDb.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | 19 | import android.content.Context 20 | import androidx.room.Database 21 | import androidx.room.Room 22 | import androidx.room.RoomDatabase 23 | 24 | @Database(entities = [CachedPurchase::class, GasTank::class, PremiumCar::class, GoldStatus::class, AugmentedSkuDetails::class], 25 | version = 1, exportSchema = false) 26 | abstract class LocalBillingDb : RoomDatabase() { 27 | abstract fun purchaseDao(): PurchaseDao 28 | abstract fun entitlementsDao(): EntitlementsDao 29 | abstract fun skuDetailsDao(): AugmentedSkuDetailsDao 30 | 31 | companion object { 32 | @Volatile 33 | private var INSTANCE: LocalBillingDb? = null 34 | 35 | fun getInstance(context: Context): LocalBillingDb = INSTANCE?: synchronized(this) { 36 | INSTANCE ?: Room.databaseBuilder( 37 | context.applicationContext, 38 | LocalBillingDb::class.java, 39 | "purchase_db") 40 | .fallbackToDestructiveMigration()//remote sources more reliable 41 | .build().also { INSTANCE=it } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /codelab-04/app/src/main/java/com/example/playbilling/trivialdrive/kotlin/billingrepo/localdb/PurchaseDao.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2018 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.playbilling.trivialdrive.kotlin.billingrepo.localdb 17 | 18 | import androidx.room.* 19 | import com.android.billingclient.api.Purchase 20 | 21 | @Dao 22 | interface PurchaseDao { 23 | @Query("SELECT * FROM purchase_table") 24 | fun getPurchases(): List 25 | 26 | @Insert 27 | fun insert(purchase: CachedPurchase) 28 | 29 | @Transaction 30 | fun insert(vararg purchases: Purchase) { 31 | purchases.forEach { 32 | insert(CachedPurchase(data = it)) 33 | } 34 | } 35 | 36 | @Delete 37 | fun delete(vararg purchases: CachedPurchase) 38 | 39 | @Query("DELETE FROM purchase_table") 40 | fun deleteAll() 41 | } -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/free_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/free_car.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gas.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gas_level_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gas_level_0.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gas_level_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gas_level_1.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gas_level_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gas_level_2.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gas_level_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gas_level_3.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gas_level_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gas_level_4.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gold_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gold_status.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/gold_subs_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/gold_subs_icon.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/premium_car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/premium_car.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/drawable-v24/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/drawable-v24/title.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 27 | 36 | 37 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/layout/fragment_make_purchase.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 26 | 29 | 35 | 38 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/navigation/navigation_graph.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | 25 | 30 | 33 | 34 | 38 | 41 | 42 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | #008577 21 | #00574B 22 | #FFCA28 23 | #FFE082 24 | #FFECB3 25 | #CFD8DC 26 | #90A4AE 27 | #263238 28 | 29 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 16dp 21 | 8dp 22 | 32dp 23 | 8dp 24 | 8dp 25 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | Trivial Drive Kotlin 19 | Hello blank fragment 20 | Fun Products 21 | Fun Subscriptions 22 | Vroooom, you drove a few miles! 23 | Oh, no! You are out of gas! Try buying some! 24 | 25 | -------------------------------------------------------------------------------- /codelab-04/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 20 | 26 | 27 | 35 | 36 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /codelab-04/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | android.enableJetifier=true 15 | android.useAndroidX=true 16 | 17 | # You can specify the keystore properties file from the command line. 18 | # Example release build using release keystore 'release-keystore.properties': 19 | # ./gradlew -PkeystorePropertiesFilename=release-keystore.properties assembleRelease 20 | # 21 | # Default source: keystore.properties 22 | # 23 | keystorePropertiesFilename=keystore.properties 24 | 25 | -------------------------------------------------------------------------------- /codelab-04/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /codelab-04/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /codelab-04/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /codelab-04/keystore.properties: -------------------------------------------------------------------------------- 1 | storeFile=kotlin_td_keystore.jks 2 | storePassword=B!llingS@mpl3 3 | keyAlias=IAB 4 | keyPassword=B!llingS@mpl3 5 | -------------------------------------------------------------------------------- /codelab-04/kotlin_td_keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/googlecodelabs/play-billing-scalable-kotlin/c87da2b89f98f76a336c2f4193f124f4384240fe/codelab-04/kotlin_td_keystore.jks -------------------------------------------------------------------------------- /codelab-04/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------