From ad79190a61d2ed72fa37d4d5858a3d9055489523 Mon Sep 17 00:00:00 2001 From: hch <16607480311@163.com> Date: Thu, 7 Dec 2023 17:46:22 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=89=E6=98=9F=E5=86=85=E8=B4=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IAP6Helper/build.gradle | 24 + IAP6Helper/proguard-rules.pro | 25 + IAP6Helper/src/main/AndroidManifest.xml | 38 ++ .../com/samsung/android/iap/IAPConnector.aidl | 19 + .../android/iap/IAPServiceCallback.aidl | 7 + .../sdk/iap/lib/activity/AccountActivity.java | 85 +++ .../sdk/iap/lib/activity/BaseActivity.java | 233 +++++++ .../lib/activity/CheckPackageActivity.java | 57 ++ .../sdk/iap/lib/activity/DialogActivity.java | 53 ++ .../sdk/iap/lib/activity/PaymentActivity.java | 127 ++++ .../iap/lib/dialog/BaseDialogFragment.java | 213 ++++++ .../sdk/iap/lib/helper/HelperDefine.java | 192 ++++++ .../iap/lib/helper/HelperListenerManager.java | 102 +++ .../sdk/iap/lib/helper/HelperUtil.java | 335 +++++++++ .../android/sdk/iap/lib/helper/IapHelper.java | 642 ++++++++++++++++++ .../sdk/iap/lib/helper/task/BaseTask.java | 65 ++ .../task/ConsumePurchasedItemsTask.java | 105 +++ .../iap/lib/helper/task/GetOwnedListTask.java | 112 +++ .../helper/task/GetProductsDetailsTask.java | 115 ++++ .../OnConsumePurchasedItemsListener.java | 20 + .../lib/listener/OnGetOwnedListListener.java | 20 + .../OnGetProductsDetailsListener.java | 20 + .../iap/lib/listener/OnIapBindListener.java | 13 + .../iap/lib/listener/OnPaymentListener.java | 15 + .../sdk/iap/lib/listener/OnSucceedBind.java | 8 + .../sdk/iap/lib/service/BaseService.java | 76 +++ .../lib/service/ConsumePurchasedItems.java | 62 ++ .../sdk/iap/lib/service/OwnedProduct.java | 63 ++ .../sdk/iap/lib/service/ProductsDetails.java | 63 ++ .../android/sdk/iap/lib/vo/BaseVo.java | 146 ++++ .../android/sdk/iap/lib/vo/ConsumeVo.java | 75 ++ .../android/sdk/iap/lib/vo/ErrorVo.java | 59 ++ .../sdk/iap/lib/vo/OwnedProductVo.java | 115 ++++ .../android/sdk/iap/lib/vo/ProductVo.java | 223 ++++++ .../android/sdk/iap/lib/vo/PurchaseVo.java | 172 +++++ .../res/color/dialog_button_text_color.xml | 7 + ...w_widget_progressbar_effect_holo_light.png | Bin 0 -> 3462 bytes .../tw_widget_progressbar_holo_light.png | Bin 0 -> 5042 bytes ...w_widget_progressbar_effect_holo_light.png | Bin 0 -> 3462 bytes .../tw_widget_progressbar_holo_light.png | Bin 0 -> 5042 bytes ...w_widget_progressbar_effect_holo_light.png | Bin 0 -> 4351 bytes .../tw_widget_progressbar_holo_light.png | Bin 0 -> 4466 bytes ...w_widget_progressbar_effect_holo_light.png | Bin 0 -> 6121 bytes .../tw_widget_progressbar_holo_light.png | Bin 0 -> 7152 bytes .../main/res/drawable/circle_60x60_dark.png | Bin 0 -> 2666 bytes .../main/res/drawable/circle_60x60_light.png | Bin 0 -> 2621 bytes .../res/drawable/dialog_button_animation.xml | 37 + .../res/drawable/dialog_full_holo_light.9.png | Bin 0 -> 2237 bytes .../main/res/drawable/dialog_radius_dark.xml | 5 + .../main/res/drawable/dialog_radius_light.xml | 5 + .../progress_dialog_animation_dark.xml | 5 + .../progress_dialog_animation_light.xml | 5 + .../main/res/drawable/progressbar_middle.xml | 19 + ...w_widget_progressbar_effect_holo_light.png | Bin 0 -> 3462 bytes .../tw_widget_progressbar_holo_light.png | Bin 0 -> 5042 bytes .../src/main/res/layout/dialog_dark.xml | 76 +++ .../src/main/res/layout/dialog_light.xml | 76 +++ .../src/main/res/layout/progress_dialog.xml | 34 + .../main/res/layout/progress_dialog_dark.xml | 29 + .../main/res/layout/progress_dialog_light.xml | 28 + IAP6Helper/src/main/res/values-ar/strings.xml | 55 ++ IAP6Helper/src/main/res/values-as/strings.xml | 55 ++ .../src/main/res/values-az-rAZ/strings.xml | 55 ++ .../src/main/res/values-be-rBY/strings.xml | 55 ++ IAP6Helper/src/main/res/values-bg/strings.xml | 55 ++ .../src/main/res/values-bn-rBD/strings.xml | 55 ++ .../src/main/res/values-bn-rIN/strings.xml | 55 ++ IAP6Helper/src/main/res/values-bo/strings.xml | 55 ++ IAP6Helper/src/main/res/values-bs/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ca/strings.xml | 55 ++ IAP6Helper/src/main/res/values-cs/strings.xml | 55 ++ IAP6Helper/src/main/res/values-da/strings.xml | 55 ++ IAP6Helper/src/main/res/values-de/strings.xml | 55 ++ IAP6Helper/src/main/res/values-el/strings.xml | 55 ++ .../src/main/res/values-en-rCA/strings.xml | 55 ++ .../src/main/res/values-en-rPH/strings.xml | 55 ++ .../src/main/res/values-en-rUS/strings.xml | 55 ++ .../src/main/res/values-en-rZG/strings.xml | 55 ++ IAP6Helper/src/main/res/values-en/strings.xml | 55 ++ .../src/main/res/values-es-rES/strings.xml | 55 ++ .../src/main/res/values-es-rUS/strings.xml | 55 ++ .../src/main/res/values-et-rEE/strings.xml | 55 ++ .../src/main/res/values-eu-rES/strings.xml | 55 ++ IAP6Helper/src/main/res/values-fa/strings.xml | 55 ++ IAP6Helper/src/main/res/values-fi/strings.xml | 55 ++ .../src/main/res/values-fr-rCA/strings.xml | 55 ++ IAP6Helper/src/main/res/values-fr/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ga/strings.xml | 55 ++ .../src/main/res/values-gl-rES/strings.xml | 55 ++ .../src/main/res/values-gu-rIN/strings.xml | 55 ++ IAP6Helper/src/main/res/values-hi/strings.xml | 55 ++ IAP6Helper/src/main/res/values-hr/strings.xml | 55 ++ IAP6Helper/src/main/res/values-hu/strings.xml | 55 ++ .../src/main/res/values-hy-rAM/strings.xml | 55 ++ IAP6Helper/src/main/res/values-in/strings.xml | 55 ++ .../src/main/res/values-is-rIS/strings.xml | 55 ++ IAP6Helper/src/main/res/values-it/strings.xml | 55 ++ IAP6Helper/src/main/res/values-iw/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ja/strings.xml | 55 ++ .../src/main/res/values-ka-rGE/strings.xml | 55 ++ .../src/main/res/values-kk-rKZ/strings.xml | 55 ++ .../src/main/res/values-km-rKH/strings.xml | 55 ++ .../src/main/res/values-kn-rIN/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ko/strings.xml | 55 ++ .../src/main/res/values-ky-rKG/strings.xml | 55 ++ .../src/main/res/values-lo-rLA/strings.xml | 55 ++ IAP6Helper/src/main/res/values-lt/strings.xml | 55 ++ IAP6Helper/src/main/res/values-lv/strings.xml | 55 ++ IAP6Helper/src/main/res/values-mg/strings.xml | 45 ++ .../src/main/res/values-mk-rMK/strings.xml | 55 ++ .../src/main/res/values-ml-rIN/strings.xml | 55 ++ .../src/main/res/values-mn-rMN/strings.xml | 55 ++ .../src/main/res/values-mr-rIN/strings.xml | 55 ++ .../src/main/res/values-ms-rMY/strings.xml | 55 ++ .../src/main/res/values-my-rMM/strings.xml | 55 ++ .../src/main/res/values-my-rZG/strings.xml | 55 ++ IAP6Helper/src/main/res/values-nb/strings.xml | 55 ++ .../src/main/res/values-ne-rNP/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ne/strings.xml | 55 ++ IAP6Helper/src/main/res/values-nl/strings.xml | 55 ++ IAP6Helper/src/main/res/values-or/strings.xml | 55 ++ .../src/main/res/values-pa-rIN/strings.xml | 55 ++ .../src/main/res/values-pl-rSP/strings.xml | 55 ++ IAP6Helper/src/main/res/values-pl/strings.xml | 55 ++ .../src/main/res/values-pt-rBR/strings.xml | 55 ++ .../src/main/res/values-pt-rPT/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ro/strings.xml | 55 ++ IAP6Helper/src/main/res/values-ru/strings.xml | 55 ++ .../src/main/res/values-si-rLK/strings.xml | 55 ++ IAP6Helper/src/main/res/values-si/strings.xml | 55 ++ IAP6Helper/src/main/res/values-sk/strings.xml | 55 ++ IAP6Helper/src/main/res/values-sl/strings.xml | 55 ++ .../src/main/res/values-sq-rAL/strings.xml | 55 ++ IAP6Helper/src/main/res/values-sr/strings.xml | 55 ++ IAP6Helper/src/main/res/values-sv/strings.xml | 55 ++ .../src/main/res/values-ta-rIN/strings.xml | 55 ++ .../src/main/res/values-te-rIN/strings.xml | 55 ++ IAP6Helper/src/main/res/values-tg/strings.xml | 55 ++ IAP6Helper/src/main/res/values-th/strings.xml | 55 ++ IAP6Helper/src/main/res/values-tk/strings.xml | 55 ++ IAP6Helper/src/main/res/values-tl/strings.xml | 55 ++ IAP6Helper/src/main/res/values-tr/strings.xml | 55 ++ .../src/main/res/values-ug-rCN/strings.xml | 31 + IAP6Helper/src/main/res/values-uk/strings.xml | 55 ++ .../src/main/res/values-ur-rPK/strings.xml | 55 ++ .../src/main/res/values-uz-rUZ/strings.xml | 55 ++ IAP6Helper/src/main/res/values-vi/strings.xml | 55 ++ .../src/main/res/values-w1920dp/integers.xml | 4 + .../src/main/res/values-w480dp/integers.xml | 4 + .../src/main/res/values-w600dp/integers.xml | 4 + .../src/main/res/values-w960dp/integers.xml | 4 + IAP6Helper/src/main/res/values-xh/strings.xml | 45 ++ .../src/main/res/values-zh-rCN/strings.xml | 55 ++ .../src/main/res/values-zh-rHK/strings.xml | 55 ++ .../src/main/res/values-zh-rTW/strings.xml | 55 ++ IAP6Helper/src/main/res/values-zu/strings.xml | 45 ++ IAP6Helper/src/main/res/values/color.xml | 13 + IAP6Helper/src/main/res/values/dimen.xml | 17 + IAP6Helper/src/main/res/values/integers.xml | 6 + IAP6Helper/src/main/res/values/strings.xml | 24 + IAP6Helper/src/main/res/values/styles.xml | 76 +++ common/build.gradle | 4 + .../common/pay/samsung/SamsungUtil.java | 62 ++ config.gradle | 2 - .../yunbao/main/activity/GoogleFragment.java | 26 +- settings.gradle | 1 + 166 files changed, 9269 insertions(+), 9 deletions(-) create mode 100644 IAP6Helper/build.gradle create mode 100644 IAP6Helper/proguard-rules.pro create mode 100644 IAP6Helper/src/main/AndroidManifest.xml create mode 100644 IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPConnector.aidl create mode 100644 IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPServiceCallback.aidl create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/AccountActivity.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/BaseActivity.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/CheckPackageActivity.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/DialogActivity.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/PaymentActivity.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/dialog/BaseDialogFragment.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperDefine.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperListenerManager.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperUtil.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/IapHelper.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/BaseTask.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/ConsumePurchasedItemsTask.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetOwnedListTask.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetProductsDetailsTask.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnConsumePurchasedItemsListener.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetOwnedListListener.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetProductsDetailsListener.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnIapBindListener.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnPaymentListener.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnSucceedBind.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/BaseService.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ConsumePurchasedItems.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/OwnedProduct.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ProductsDetails.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/BaseVo.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ConsumeVo.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ErrorVo.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/OwnedProductVo.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ProductVo.java create mode 100644 IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/PurchaseVo.java create mode 100644 IAP6Helper/src/main/res/color/dialog_button_text_color.xml create mode 100644 IAP6Helper/src/main/res/drawable-hdpi/tw_widget_progressbar_effect_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-hdpi/tw_widget_progressbar_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-mdpi/tw_widget_progressbar_effect_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-mdpi/tw_widget_progressbar_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-xhdpi/tw_widget_progressbar_effect_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-xhdpi/tw_widget_progressbar_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-xxhdpi/tw_widget_progressbar_effect_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable-xxhdpi/tw_widget_progressbar_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable/circle_60x60_dark.png create mode 100644 IAP6Helper/src/main/res/drawable/circle_60x60_light.png create mode 100644 IAP6Helper/src/main/res/drawable/dialog_button_animation.xml create mode 100644 IAP6Helper/src/main/res/drawable/dialog_full_holo_light.9.png create mode 100644 IAP6Helper/src/main/res/drawable/dialog_radius_dark.xml create mode 100644 IAP6Helper/src/main/res/drawable/dialog_radius_light.xml create mode 100644 IAP6Helper/src/main/res/drawable/progress_dialog_animation_dark.xml create mode 100644 IAP6Helper/src/main/res/drawable/progress_dialog_animation_light.xml create mode 100644 IAP6Helper/src/main/res/drawable/progressbar_middle.xml create mode 100644 IAP6Helper/src/main/res/drawable/tw_widget_progressbar_effect_holo_light.png create mode 100644 IAP6Helper/src/main/res/drawable/tw_widget_progressbar_holo_light.png create mode 100644 IAP6Helper/src/main/res/layout/dialog_dark.xml create mode 100644 IAP6Helper/src/main/res/layout/dialog_light.xml create mode 100644 IAP6Helper/src/main/res/layout/progress_dialog.xml create mode 100644 IAP6Helper/src/main/res/layout/progress_dialog_dark.xml create mode 100644 IAP6Helper/src/main/res/layout/progress_dialog_light.xml create mode 100644 IAP6Helper/src/main/res/values-ar/strings.xml create mode 100644 IAP6Helper/src/main/res/values-as/strings.xml create mode 100644 IAP6Helper/src/main/res/values-az-rAZ/strings.xml create mode 100644 IAP6Helper/src/main/res/values-be-rBY/strings.xml create mode 100644 IAP6Helper/src/main/res/values-bg/strings.xml create mode 100644 IAP6Helper/src/main/res/values-bn-rBD/strings.xml create mode 100644 IAP6Helper/src/main/res/values-bn-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-bo/strings.xml create mode 100644 IAP6Helper/src/main/res/values-bs/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ca/strings.xml create mode 100644 IAP6Helper/src/main/res/values-cs/strings.xml create mode 100644 IAP6Helper/src/main/res/values-da/strings.xml create mode 100644 IAP6Helper/src/main/res/values-de/strings.xml create mode 100644 IAP6Helper/src/main/res/values-el/strings.xml create mode 100644 IAP6Helper/src/main/res/values-en-rCA/strings.xml create mode 100644 IAP6Helper/src/main/res/values-en-rPH/strings.xml create mode 100644 IAP6Helper/src/main/res/values-en-rUS/strings.xml create mode 100644 IAP6Helper/src/main/res/values-en-rZG/strings.xml create mode 100644 IAP6Helper/src/main/res/values-en/strings.xml create mode 100644 IAP6Helper/src/main/res/values-es-rES/strings.xml create mode 100644 IAP6Helper/src/main/res/values-es-rUS/strings.xml create mode 100644 IAP6Helper/src/main/res/values-et-rEE/strings.xml create mode 100644 IAP6Helper/src/main/res/values-eu-rES/strings.xml create mode 100644 IAP6Helper/src/main/res/values-fa/strings.xml create mode 100644 IAP6Helper/src/main/res/values-fi/strings.xml create mode 100644 IAP6Helper/src/main/res/values-fr-rCA/strings.xml create mode 100644 IAP6Helper/src/main/res/values-fr/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ga/strings.xml create mode 100644 IAP6Helper/src/main/res/values-gl-rES/strings.xml create mode 100644 IAP6Helper/src/main/res/values-gu-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-hi/strings.xml create mode 100644 IAP6Helper/src/main/res/values-hr/strings.xml create mode 100644 IAP6Helper/src/main/res/values-hu/strings.xml create mode 100644 IAP6Helper/src/main/res/values-hy-rAM/strings.xml create mode 100644 IAP6Helper/src/main/res/values-in/strings.xml create mode 100644 IAP6Helper/src/main/res/values-is-rIS/strings.xml create mode 100644 IAP6Helper/src/main/res/values-it/strings.xml create mode 100644 IAP6Helper/src/main/res/values-iw/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ja/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ka-rGE/strings.xml create mode 100644 IAP6Helper/src/main/res/values-kk-rKZ/strings.xml create mode 100644 IAP6Helper/src/main/res/values-km-rKH/strings.xml create mode 100644 IAP6Helper/src/main/res/values-kn-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ko/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ky-rKG/strings.xml create mode 100644 IAP6Helper/src/main/res/values-lo-rLA/strings.xml create mode 100644 IAP6Helper/src/main/res/values-lt/strings.xml create mode 100644 IAP6Helper/src/main/res/values-lv/strings.xml create mode 100644 IAP6Helper/src/main/res/values-mg/strings.xml create mode 100644 IAP6Helper/src/main/res/values-mk-rMK/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ml-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-mn-rMN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-mr-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ms-rMY/strings.xml create mode 100644 IAP6Helper/src/main/res/values-my-rMM/strings.xml create mode 100644 IAP6Helper/src/main/res/values-my-rZG/strings.xml create mode 100644 IAP6Helper/src/main/res/values-nb/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ne-rNP/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ne/strings.xml create mode 100644 IAP6Helper/src/main/res/values-nl/strings.xml create mode 100644 IAP6Helper/src/main/res/values-or/strings.xml create mode 100644 IAP6Helper/src/main/res/values-pa-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-pl-rSP/strings.xml create mode 100644 IAP6Helper/src/main/res/values-pl/strings.xml create mode 100644 IAP6Helper/src/main/res/values-pt-rBR/strings.xml create mode 100644 IAP6Helper/src/main/res/values-pt-rPT/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ro/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ru/strings.xml create mode 100644 IAP6Helper/src/main/res/values-si-rLK/strings.xml create mode 100644 IAP6Helper/src/main/res/values-si/strings.xml create mode 100644 IAP6Helper/src/main/res/values-sk/strings.xml create mode 100644 IAP6Helper/src/main/res/values-sl/strings.xml create mode 100644 IAP6Helper/src/main/res/values-sq-rAL/strings.xml create mode 100644 IAP6Helper/src/main/res/values-sr/strings.xml create mode 100644 IAP6Helper/src/main/res/values-sv/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ta-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-te-rIN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-tg/strings.xml create mode 100644 IAP6Helper/src/main/res/values-th/strings.xml create mode 100644 IAP6Helper/src/main/res/values-tk/strings.xml create mode 100644 IAP6Helper/src/main/res/values-tl/strings.xml create mode 100644 IAP6Helper/src/main/res/values-tr/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ug-rCN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-uk/strings.xml create mode 100644 IAP6Helper/src/main/res/values-ur-rPK/strings.xml create mode 100644 IAP6Helper/src/main/res/values-uz-rUZ/strings.xml create mode 100644 IAP6Helper/src/main/res/values-vi/strings.xml create mode 100644 IAP6Helper/src/main/res/values-w1920dp/integers.xml create mode 100644 IAP6Helper/src/main/res/values-w480dp/integers.xml create mode 100644 IAP6Helper/src/main/res/values-w600dp/integers.xml create mode 100644 IAP6Helper/src/main/res/values-w960dp/integers.xml create mode 100644 IAP6Helper/src/main/res/values-xh/strings.xml create mode 100644 IAP6Helper/src/main/res/values-zh-rCN/strings.xml create mode 100644 IAP6Helper/src/main/res/values-zh-rHK/strings.xml create mode 100644 IAP6Helper/src/main/res/values-zh-rTW/strings.xml create mode 100644 IAP6Helper/src/main/res/values-zu/strings.xml create mode 100644 IAP6Helper/src/main/res/values/color.xml create mode 100644 IAP6Helper/src/main/res/values/dimen.xml create mode 100644 IAP6Helper/src/main/res/values/integers.xml create mode 100644 IAP6Helper/src/main/res/values/strings.xml create mode 100644 IAP6Helper/src/main/res/values/styles.xml create mode 100644 common/src/main/java/com/yunbao/common/pay/samsung/SamsungUtil.java diff --git a/IAP6Helper/build.gradle b/IAP6Helper/build.gradle new file mode 100644 index 000000000..d8fc4749a --- /dev/null +++ b/IAP6Helper/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.library' +android { + compileSdkVersion rootProject.ext.android.compileSdkVersion + buildToolsVersion rootProject.ext.android.buildToolsVersion + defaultConfig { + minSdkVersion minSdkVersion + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + versionCode versionCode + versionName versionName + targetSdkVersion targetSdkVersion + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { +} \ No newline at end of file diff --git a/IAP6Helper/proguard-rules.pro b/IAP6Helper/proguard-rules.pro new file mode 100644 index 000000000..7e9e287fb --- /dev/null +++ b/IAP6Helper/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\sbkim\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/IAP6Helper/src/main/AndroidManifest.xml b/IAP6Helper/src/main/AndroidManifest.xml new file mode 100644 index 000000000..b5f9f1046 --- /dev/null +++ b/IAP6Helper/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPConnector.aidl b/IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPConnector.aidl new file mode 100644 index 000000000..89f375057 --- /dev/null +++ b/IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPConnector.aidl @@ -0,0 +1,19 @@ +package com.samsung.android.iap; + +import com.samsung.android.iap.IAPServiceCallback; + +interface IAPConnector { + + boolean requestCmd(IAPServiceCallback callback, in Bundle bundle); + + boolean unregisterCallback(IAPServiceCallback callback); + + ///////////////////////////// IAP 5.0 + Bundle getProductsDetails(String packageName, String itemIds, int pagingIndex, int mode); + + Bundle getOwnedList(String packageName, String itemType, int pagingIndex, int mode); + + Bundle consumePurchasedItems(String packageName, String purchaseIds, int mode); + + Bundle requestServiceAPI(String packageName, String requestId, String extraData); +} diff --git a/IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPServiceCallback.aidl b/IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPServiceCallback.aidl new file mode 100644 index 000000000..c37123350 --- /dev/null +++ b/IAP6Helper/src/main/aidl/com/samsung/android/iap/IAPServiceCallback.aidl @@ -0,0 +1,7 @@ +package com.samsung.android.iap; + +import android.os.Bundle; + +interface IAPServiceCallback { + oneway void responseCallback(in Bundle bundle); +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/AccountActivity.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/AccountActivity.java new file mode 100644 index 000000000..4ce2f87a2 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/AccountActivity.java @@ -0,0 +1,85 @@ +package com.samsung.android.sdk.iap.lib.activity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; + +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.HelperUtil; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; + +/** + * Created by sangbum7.kim on 2018-03-06. + */ + +public class AccountActivity extends Activity { + private static final String TAG = AccountActivity.class.getSimpleName(); + + IapHelper mIapHelper = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mIapHelper = IapHelper.getInstance(this); + // ==================================================================== + // 1. If IAP package is installed and valid, start SamsungAccount + // authentication activity to start purchase. + // ==================================================================== + Log.i(TAG, "Samsung Account Login..."); + HelperUtil.startAccountActivity(this); + // ==================================================================== + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + @Override + protected void onActivityResult(int _requestCode, int _resultCode, Intent intent) { + Log.i(TAG, "onActivityResult>> requestCode : " + _requestCode + ", resultCode : " + _resultCode); + switch (_requestCode) { + case HelperDefine.REQUEST_CODE_IS_ACCOUNT_CERTIFICATION: + Log.i(TAG, "REQUEST_CODE_IS_ACCOUNT_CERTIFICATION Result : " + _resultCode); + // 1) If SamsungAccount authentication is succeed + // ------------------------------------------------------------ + if (RESULT_OK == _resultCode) { + // bind to IAPService + // -------------------------------------------------------- + Runnable runProcess = new Runnable() { + @Override + public void run() { + mIapHelper.bindIapService(); + } + }; + runProcess.run(); + + finish(); + overridePendingTransition(0, 0); + // -------------------------------------------------------- + } + // ------------------------------------------------------------ + // 2) If SamsungAccount authentication is cancelled + // ------------------------------------------------------------ + else { +// Runnable runProcess = new Runnable() { +// @Override +// public void run() { +// if(mIapHelper.getServiceProcess() != null) +// mIapHelper.getServiceProcess().onEndProcess(); +// else +// mIapHelper.dispose(); +// } +// }; +// if(runProcess!=null) +// runProcess.run(); +// else + mIapHelper.dispose(); + finish(); + } + break; + } + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/BaseActivity.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/BaseActivity.java new file mode 100644 index 000000000..10e581604 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/BaseActivity.java @@ -0,0 +1,233 @@ +package com.samsung.android.sdk.iap.lib.activity; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.widget.Toast; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.dialog.BaseDialogFragment; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.HelperUtil; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; +import com.samsung.android.sdk.iap.lib.vo.PurchaseVo; + + +public abstract class BaseActivity extends Activity { + private static final String TAG = BaseActivity.class.getSimpleName(); + + protected ErrorVo mErrorVo = new ErrorVo(); + private Dialog mProgressDialog = null; + protected PurchaseVo mPurchaseVo = null; + + /** + * Helper Class between IAPService and 3rd Party Application + */ + IapHelper mIapHelper = null; + + /** + * Flag value to show successful pop-up. Error pop-up appears whenever it fails or not. + */ + protected boolean mShowErrorDialog = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + // 1. IapHelper Instance creation + // To test on development, set mode to test mode using + // use HelperDefine.OperationMode.OPERATION_MODE_TEST or + // HelperDefine.OperationMode.OPERATION_MODE_TEST_FAILURE constants. + // ==================================================================== + mIapHelper = IapHelper.getInstance(this); + // ==================================================================== + + // 2. This activity is invisible excepting progress bar as default. + // ==================================================================== + try { + Toast.makeText(this, + R.string.dream_sapps_body_authenticating_ing, + Toast.LENGTH_LONG).show(); + } catch (Exception e) { + e.printStackTrace(); + } + // ==================================================================== + + super.onCreate(savedInstanceState); + } + + public void setErrorVo(ErrorVo _errorVo) { + mErrorVo = _errorVo; + } + + public boolean checkAppsPackage(Activity _activity) { + // 1. If Galaxy Store is installed + // ==================================================================== + if (HelperUtil.isInstalledAppsPackage(this)) { + // 1) If Galaxy Store is enabled + // ================================================================ + if (!HelperUtil.isEnabledAppsPackage(this)) { + HelperUtil.showEnableGalaxyStoreDialog(_activity); + // ================================================================ + // 2) If Galaxy Store is valid + // ================================================================ + } else if (HelperUtil.isValidAppsPackage(this)) { + return true; + } else { + // Set error to notify result to third-party application + // ------------------------------------------------------------ + final String ERROR_ISSUER_IAP_CLIENT = "IC"; + final int ERROR_CODE_INVALID_GALAXY_STORE = 10002; + String errorString = String.format( + getString( + R.string.dream_ph_body_contact_p1sscustomer_servicep2ss_for_more_information_n_nerror_code_c_p3ss), + "", "", ERROR_ISSUER_IAP_CLIENT + ERROR_CODE_INVALID_GALAXY_STORE); + mErrorVo.setError(HelperDefine.IAP_PAYMENT_IS_CANCELED, errorString); + HelperUtil.showInvalidGalaxyStoreDialog(this); + } + // ================================================================ + + // ==================================================================== + // 2. If Galaxy Store is not installed + // ==================================================================== + } else { + HelperUtil.installAppsPackage(this); + } + // ==================================================================== + return false; + } + + /** + * dispose IapHelper {@link PaymentActivity} To do that, preDestory must be invoked at first in onDestory of each child activity + */ + protected void preDestory() { + // 1. Invoke dispose Method to unbind service and release inprogress flag + // ==================================================================== + if (mIapHelper != null) { + mIapHelper.dispose(); + mIapHelper = null; + } + } + + @Override + protected void onDestroy() { + // 1. dismiss ProgressDialog + // ==================================================================== + try { + if (mProgressDialog != null) { + mProgressDialog.dismiss(); + mProgressDialog = null; + } + } catch (Exception e) { + e.printStackTrace(); + } + // ==================================================================== + + super.onDestroy(); + } + + @Override + public void finish() { + super.finish(); + overridePendingTransition(0, 0); + } + + protected void finishPurchase(Intent _intent) { + // 1. If there is bundle passed from IAP + // ==================================================================== + if (_intent != null && _intent.getExtras() != null) { + Bundle extras = _intent.getExtras(); + mErrorVo.setError( + extras.getInt(HelperDefine.KEY_NAME_STATUS_CODE), + extras.getString(HelperDefine.KEY_NAME_ERROR_STRING), + extras.getString(HelperDefine.KEY_NAME_ERROR_DETAILS, "")); + + // 1) If the purchase is successful, + // ---------------------------------------------------------------- + if (mErrorVo.getErrorCode() == HelperDefine.IAP_ERROR_NONE) { + mPurchaseVo = new PurchaseVo(extras.getString( + HelperDefine.KEY_NAME_RESULT_OBJECT)); + + mErrorVo.setError( + HelperDefine.IAP_ERROR_NONE, + getString(R.string.dream_sapps_body_your_purchase_is_complete)); + + finish(); + } + // ---------------------------------------------------------------- + // 2) If the purchase is failed + // ---------------------------------------------------------------- + else { + Log.e(TAG, "finishPurchase: " + mErrorVo.dump()); + if (mShowErrorDialog) { + HelperUtil.showIapErrorDialog( + this, + getString(R.string.dream_ph_pheader_couldnt_complete_purchase), + mErrorVo.getErrorString(), + mErrorVo.getErrorDetailsString(), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + finish(); + } + }, + null); + } else { + finish(); + } + } + // ---------------------------------------------------------------- + } + // ==================================================================== + // 2. If there is no bundle passed from IAP + // ==================================================================== + else { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + getString(R.string.mids_sapps_pop_unknown_error_occurred)); + + if (mShowErrorDialog) { + HelperUtil.showIapErrorDialog( + this, + getString(R.string.dream_ph_pheader_couldnt_complete_purchase), + getString(R.string.mids_sapps_pop_unknown_error_occurred), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + finish(); + } + }, + null); + } else { + finish(); + } + + return; + } + // ==================================================================== + } + + protected void cancelPurchase(Intent intent) { + if (intent != null) { + Bundle extras = intent.getExtras(); + if (extras != null) { + mErrorVo.setError( + extras.getInt( + HelperDefine.KEY_NAME_STATUS_CODE, + HelperDefine.IAP_PAYMENT_IS_CANCELED), + extras.getString( + HelperDefine.KEY_NAME_ERROR_STRING, + getString(R.string.mids_sapps_pop_payment_canceled)), + extras.getString(HelperDefine.KEY_NAME_ERROR_DETAILS, "")); + finish(); + return; + } + } + + mErrorVo.setError( + HelperDefine.IAP_PAYMENT_IS_CANCELED, + getString(R.string.mids_sapps_pop_payment_canceled)); + finish(); + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/CheckPackageActivity.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/CheckPackageActivity.java new file mode 100644 index 000000000..e790a63d0 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/CheckPackageActivity.java @@ -0,0 +1,57 @@ +package com.samsung.android.sdk.iap.lib.activity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.HelperUtil; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; + +/** + * Created by sangbum7.kim on 2018-03-07. + */ + +public class CheckPackageActivity extends Activity { + private static final String TAG = CheckPackageActivity.class.getSimpleName(); + private boolean mFinishFlag = true; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mFinishFlag = true; + Intent intent = getIntent(); + if (intent != null) { + Bundle extras = intent.getExtras(); + if (extras != null) { + int DialogType = extras.getInt("DialogType"); + switch (DialogType) { + case HelperDefine.DIALOG_TYPE_INVALID_PACKAGE: { + HelperUtil.showInvalidGalaxyStoreDialog(this); + mFinishFlag = false; + } + break; + case HelperDefine.DIALOG_TYPE_DISABLE_APPLICATION: { + HelperUtil.showEnableGalaxyStoreDialog(this); + mFinishFlag = false; + } + break; + case HelperDefine.DIALOG_TYPE_APPS_DETAIL: { + HelperUtil.showUpdateGalaxyStoreDialog(this); + mFinishFlag = false; + } + break; + } + } + } + if (mFinishFlag) { + finish(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + IapHelper.getInstance(getApplicationContext()).dispose(); + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/DialogActivity.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/DialogActivity.java new file mode 100644 index 000000000..8e77cfa79 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/DialogActivity.java @@ -0,0 +1,53 @@ +package com.samsung.android.sdk.iap.lib.activity; + +import android.app.Activity; +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.dialog.BaseDialogFragment; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.HelperUtil; + +/** + * Created by sangbum7.kim on 2018-03-05. + */ + +public class DialogActivity extends Activity { + private static final String TAG = DialogActivity.class.getSimpleName(); + private String mExtraString = ""; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Intent intent = getIntent(); + if (intent != null) { + Bundle extras = intent.getExtras(); + if (extras != null) { + if (HelperDefine.DIALOG_TYPE_NOTIFICATION == extras.getInt("DialogType")) { + String title = extras.getString("Title"); + String message = extras.getString("Message"); + HelperUtil.showIapErrorDialog( + this, + title, + message, + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + finish(); + } + }, + null); + } + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/PaymentActivity.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/PaymentActivity.java new file mode 100644 index 000000000..e309aa00c --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/activity/PaymentActivity.java @@ -0,0 +1,127 @@ +package com.samsung.android.sdk.iap.lib.activity; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Bundle; +import android.util.Log; +import android.widget.Toast; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.HelperListenerManager; +import com.samsung.android.sdk.iap.lib.listener.OnPaymentListener; + +public class PaymentActivity extends BaseActivity { + private static final String TAG = PaymentActivity.class.getSimpleName(); + + private String mItemId = null; + private String mPassThroughParam = ""; + private int mMode; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (intent != null && intent.getExtras() != null + && intent.getExtras().containsKey("ItemId")) { + Bundle extras = intent.getExtras(); + mItemId = extras.getString("ItemId"); + mPassThroughParam = extras.getString("PassThroughParam"); + mShowErrorDialog = extras.getBoolean("ShowErrorDialog", true); + mMode = extras.getInt("OperationMode", HelperDefine.OperationMode.OPERATION_MODE_PRODUCTION.getValue()); + } else { + Toast.makeText(this, + R.string.mids_sapps_pop_an_invalid_value_has_been_provided_for_samsung_in_app_purchase, + Toast.LENGTH_LONG).show(); + + // Set error to pass result to third-party application + // ---------------------------------------------------------------- + mErrorVo.setError(HelperDefine.IAP_ERROR_COMMON, + getString(R.string.mids_sapps_pop_an_invalid_value_has_been_provided_for_samsung_in_app_purchase)); + // ---------------------------------------------------------------- + + finish(); + } + + if (checkAppsPackage(this)) { + startPaymentActivity(); + } + } + + @Override + protected void onDestroy() { + super.preDestory(); + if (isFinishing()) { + OnPaymentListener onPaymentListener = + HelperListenerManager.getInstance().getOnPaymentListener(); + HelperListenerManager.getInstance().setOnPaymentListener(null); + if (null != onPaymentListener) { + onPaymentListener.onPayment(mErrorVo, mPurchaseVo); + } + } + super.onDestroy(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + } + + @Override + protected void onActivityResult(int _requestCode, int _resultCode, Intent _intent) { + switch (_requestCode) { + case HelperDefine.REQUEST_CODE_IS_IAP_PAYMENT: { + if (_resultCode == RESULT_OK) { + finishPurchase(_intent); + } + else if (_resultCode == RESULT_CANCELED) { + Log.e(TAG, "Payment is canceled."); + cancelPurchase(_intent); + } + break; + } + case HelperDefine.REQUEST_CODE_IS_ENABLE_APPS: { + if (checkAppsPackage(this)) { + startPaymentActivity(); + } + break; + } + } + } + + private void startPaymentActivity() { + if (mIapHelper == null) { + Log.e(TAG, "Fail to get IAP Helper instance"); + return; + } + try { + Context context = this.getApplicationContext(); + Bundle bundle = new Bundle(); + bundle.putString(HelperDefine.KEY_NAME_THIRD_PARTY_NAME, context.getPackageName()); + bundle.putString(HelperDefine.KEY_NAME_ITEM_ID, mItemId); + if (mPassThroughParam != null) { + bundle.putString(HelperDefine.KEY_NAME_PASSTHROUGH_ID, mPassThroughParam); + } + bundle.putInt(HelperDefine.KEY_NAME_OPERATION_MODE, mMode); + bundle.putString(HelperDefine.KEY_NAME_VERSION_CODE, HelperDefine.HELPER_VERSION); + + ComponentName com = new ComponentName(HelperDefine.GALAXY_PACKAGE_NAME, + HelperDefine.IAP_PACKAGE_NAME + ".activity.PaymentMethodListActivity"); + + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.setComponent(com); + + intent.putExtras(bundle); + + if (intent.resolveActivity(context.getPackageManager()) != null) { + startActivityForResult(intent, HelperDefine.REQUEST_CODE_IS_IAP_PAYMENT); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/dialog/BaseDialogFragment.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/dialog/BaseDialogFragment.java new file mode 100644 index 000000000..8f2977cd3 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/dialog/BaseDialogFragment.java @@ -0,0 +1,213 @@ +package com.samsung.android.sdk.iap.lib.dialog; + +import android.app.ActionBar; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.TextView; + +import com.samsung.android.sdk.iap.lib.R; + +public class BaseDialogFragment extends DialogFragment implements View.OnClickListener { + private static final String TAG = BaseDialogFragment.class.getSimpleName(); + + private int dialogWidth; + private String title; + private CharSequence message; + private String messageExtra = ""; + private String positiveBtnText; + private String negativeBtnText; + private OnClickListener positiveButtonListener = null; + private OnClickListener negativeButtonListener = null; + + public static final String IAP_DIALOG_TAG = "IAP_dialog"; + + public interface OnClickListener { + void onClick(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public void onResume() { + super.onResume(); + dialogWidth = getDialogWidth(); + getDialog().getWindow().setLayout(dialogWidth, ActionBar.LayoutParams.WRAP_CONTENT); + } + + @Override + public void onDestroyView() { + if (getDialog() != null && getRetainInstance()) { + getDialog().setDismissMessage(null); + } + super.onDestroyView(); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + View view; + if (isDarkMode()) { + view = getActivity().getLayoutInflater().inflate(R.layout.dialog_dark, null); + } else { + view = getActivity().getLayoutInflater().inflate(R.layout.dialog_light, null); + } + + ((TextView) view.findViewById(R.id.dialog_title)).setText(title); + ((TextView) view.findViewById(R.id.dialog_message)).setText(message); + ((TextView) view.findViewById(R.id.dialog_message)).setLinksClickable(true); + ((TextView) view.findViewById(R.id.dialog_message)).setMovementMethod(LinkMovementMethod.getInstance()); + + if (messageExtra == null || messageExtra.isEmpty()) { + view.findViewById(R.id.dialog_message_extra).setVisibility(View.GONE); + } else { + ((TextView) view.findViewById(R.id.dialog_message_extra)) + .setText(getString(R.string.ids_com_body_error_code_c) + " " + messageExtra); + view.findViewById(R.id.dialog_message_extra).setVisibility(View.VISIBLE); + } + + ((Button) view.findViewById(R.id.dialog_ok_btn)).setText(positiveBtnText); + view.findViewById(R.id.dialog_ok_btn).setOnClickListener(this); + + if (negativeButtonListener == null) { + view.findViewById(R.id.dialog_cancel_btn).setVisibility(View.GONE); + view.findViewById(R.id.dialog_btn_padding).setVisibility(View.GONE); + } else { + ((Button) view.findViewById(R.id.dialog_cancel_btn)).setText(negativeBtnText); + view.findViewById(R.id.dialog_cancel_btn).setVisibility(View.VISIBLE); + view.findViewById(R.id.dialog_cancel_btn).setOnClickListener(this); + view.findViewById(R.id.dialog_btn_padding).setVisibility(View.VISIBLE); + } + + Dialog dialog = new Dialog(getActivity(), R.style.Theme_DialogTransparent); + dialog.setContentView(view); + dialog.setCancelable(false); + dialog.setCanceledOnTouchOutside(false); + + dialog.getWindow().setGravity(Gravity.BOTTOM); + dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + TypedValue dimValue = new TypedValue(); + if (isDarkMode()) { + getResources().getValue(R.integer.dim_dark, dimValue, true); + } else { + getResources().getValue(R.integer.dim_light, dimValue, true); + } + dialog.getWindow().setDimAmount(dimValue.getFloat()); + + return dialog; + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + dialogWidth = getDialogWidth(); + getDialog().getWindow().setLayout(dialogWidth, ActionBar.LayoutParams.WRAP_CONTENT); + } + + public BaseDialogFragment setDialogTitle(String _title) { + if (!TextUtils.isEmpty(_title)) { + this.title = _title; + } + return this; + } + + public BaseDialogFragment setDialogMessageText(CharSequence _message) { + if (!TextUtils.isEmpty(_message)) { + this.message = _message; + } + return this; + } + + public BaseDialogFragment setDialogMessageExtra(String _extra) { + if (!TextUtils.isEmpty(_extra)) { + this.messageExtra = _extra; + } + return this; + } + + public BaseDialogFragment setDialogPositiveButton(String _positiveBtnText, final OnClickListener listener) { + if (!TextUtils.isEmpty(_positiveBtnText)) { + positiveBtnText = _positiveBtnText; + } else { + positiveBtnText = (String) getText(android.R.string.ok); + } + if (listener != null) { + positiveButtonListener = listener; + } + return this; + } + + public BaseDialogFragment setDialogNegativeButton(String _negativeBtnText, final OnClickListener listener) { + if (!TextUtils.isEmpty(_negativeBtnText)) { + negativeBtnText = _negativeBtnText; + } + if (listener != null) { + negativeButtonListener = listener; + } + return this; + } + + @Override + public void onClick(View v) { + if (v.getId() == R.id.dialog_ok_btn) { + Runnable OkBtnRunnable = new Runnable() { + @Override + public void run() { + positiveButtonListener.onClick(); + } + }; + OkBtnRunnable.run(); + } else if (v.getId() == R.id.dialog_cancel_btn) { + Runnable CancelBtnRunnable = new Runnable() { + @Override + public void run() { + negativeButtonListener.onClick(); + } + }; + CancelBtnRunnable.run(); + } + dismiss(); + } + + private int getDialogWidth() { + TypedValue outValue = new TypedValue(); + getResources().getValue(R.integer.dialog_width_percentage, outValue, true); + float ratio = outValue.getFloat(); + int width = (int) (getResources().getDisplayMetrics().widthPixels * ratio); + return width; + } + + private boolean isDarkMode() { + try { + // getContext() requires M OS or higher version + int nightModeFlags = 0; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + nightModeFlags = getContext().getResources().getConfiguration().uiMode & + Configuration.UI_MODE_NIGHT_MASK; + } + switch (nightModeFlags) { + case Configuration.UI_MODE_NIGHT_YES: + return true; + case Configuration.UI_MODE_NIGHT_NO: + case Configuration.UI_MODE_NIGHT_UNDEFINED: + default: + return false; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperDefine.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperDefine.java new file mode 100644 index 000000000..15a86549d --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperDefine.java @@ -0,0 +1,192 @@ +package com.samsung.android.sdk.iap.lib.helper; + +/** + * Created by sangbum7.kim on 2017-07-17. + */ + +public class HelperDefine { + public static final String HELPER_VERSION = "6.1.0.004"; + // IAP Signature HashCode - Used to validate IAP package + // ======================================================================== + public static final int APPS_SIGNATURE_HASHCODE = 0x79998D13; + public static final int APPS_PACKAGE_VERSION = 450301000; + public static final int APPS_PACKAGE_VERSION_GO = 510130000; + public static final int APPS_PACKAGE_VERSION_INDIA = 660107000; + + // ======================================================================== + + // Name of IAP Package and Service + // ======================================================================== + public static final String GALAXY_PACKAGE_NAME = "com.sec.android.app.samsungapps"; + public static final String IAP_PACKAGE_NAME = "com.samsung.android.iap"; + public static final String IAP_SERVICE_NAME = + "com.samsung.android.iap.service.IAPService"; + // ======================================================================== + + // result code for binding to IAPService + // ======================================================================== + public static final int IAP_RESPONSE_RESULT_OK = 0; + public static final int IAP_RESPONSE_RESULT_UNAVAILABLE = 2; + // ======================================================================== + + // BUNDLE KEY + // ======================================================================== + public static final String KEY_NAME_THIRD_PARTY_NAME = "THIRD_PARTY_NAME"; + public static final String KEY_NAME_STATUS_CODE = "STATUS_CODE"; + public static final String KEY_NAME_ERROR_STRING = "ERROR_STRING"; + public static final String KEY_NAME_ERROR_DETAILS = "ERROR_DETAILS"; + public static final String KEY_NAME_ITEM_ID = "ITEM_ID"; + public static final String KEY_NAME_PASSTHROUGH_ID = "PASSTHROUGH_ID"; + public static final String KEY_NAME_RESULT_LIST = "RESULT_LIST"; + public static final String KEY_NAME_OPERATION_MODE = "OPERATION_MODE"; + public static final String KEY_NAME_RESULT_OBJECT = "RESULT_OBJECT"; + public static final String KEY_NAME_VERSION_CODE = "VERSION_CODE"; + public static final String NEXT_PAGING_INDEX = "NEXT_PAGING_INDEX"; + // ======================================================================== + + // Item Type + // ======================================================================== + public static final String PRODUCT_TYPE_ITEM = "item"; + public static final String PRODUCT_TYPE_SUBSCRIPTION = "subscription"; + public static final String PRODUCT_TYPE_ALL = "all"; + + // Define request code to IAPService. + // ======================================================================== + public static final int REQUEST_CODE_IS_IAP_PAYMENT = 1; + public static final int REQUEST_CODE_IS_ACCOUNT_CERTIFICATION = 2; + public static final int REQUEST_CODE_IS_ENABLE_APPS = 3; + // ======================================================================== + + // Define dialog type to DialogActivity + public static final int DIALOG_TYPE_NONE = 0; + public static final int DIALOG_TYPE_NOTIFICATION = 1; + public static final int DIALOG_TYPE_INVALID_PACKAGE = 2; + public static final int DIALOG_TYPE_DISABLE_APPLICATION = 3; + public static final int DIALOG_TYPE_APPS_DETAIL = 4; + + // Define request parameter to IAPService + // ======================================================================== + public static final int PASSTHROGUH_MAX_LENGTH = 255; + // ======================================================================== + + // Define status code notify to 3rd-party application + // ======================================================================== + /** + * Success + */ + final public static int IAP_ERROR_NONE = 0; + + /** + * Payment is cancelled + */ + final public static int IAP_PAYMENT_IS_CANCELED = 1; + + /** + * IAP initialization error + */ + final public static int IAP_ERROR_INITIALIZATION = -1000; + + /** + * IAP need to be upgraded + */ + final public static int IAP_ERROR_NEED_APP_UPGRADE = -1001; + + /** + * Common error + */ + final public static int IAP_ERROR_COMMON = -1002; + + /** + * Repurchase NON-CONSUMABLE item + */ + final public static int IAP_ERROR_ALREADY_PURCHASED = -1003; + + /** + * When PaymentMethodList Activity is called without Bundle data + */ + final public static int IAP_ERROR_WHILE_RUNNING = -1004; + + /** + * does not exist item or item group id + */ + final public static int IAP_ERROR_PRODUCT_DOES_NOT_EXIST = -1005; + + /** + * After purchase request not received the results can not be determined whether to buy. So, the confirmation of purchase list is needed. + */ + final public static int IAP_ERROR_CONFIRM_INBOX = -1006; + + /** + * Error when item group id does not exist + */ + public static final int IAP_ERROR_ITEM_GROUP_DOES_NOT_EXIST = -1007; + + /** + * Error when network is not available + */ + public static final int IAP_ERROR_NETWORK_NOT_AVAILABLE = -1008; + + /** + * IOException + */ + public static final int IAP_ERROR_IOEXCEPTION_ERROR = -1009; + + /** + * SocketTimeoutException + */ + public static final int IAP_ERROR_SOCKET_TIMEOUT = -1010; + + /** + * ConnectTimeoutException + */ + public static final int IAP_ERROR_CONNECT_TIMEOUT = -1011; + + /** + * The Item is not for sale in the country + */ + public static final int IAP_ERROR_NOT_EXIST_LOCAL_PRICE = -1012; + + /** + * IAP is not serviced in the country + */ + public static final int IAP_ERROR_NOT_AVAILABLE_SHOP = -1013; + + /** + * SA not logged in + */ + public static final int IAP_ERROR_NEED_SA_LOGIN = -1014; + // ======================================================================== + + /** + * initial state + */ + protected static final int STATE_TERM = 0; + + /** + * state of bound to IAPService successfully + */ + protected static final int STATE_BINDING = 1; + + /** + * state of InitIapTask successfully finished + */ + protected static final int STATE_READY = 2; + // ======================================================================== + + // IAP Operation Mode + // ======================================================================== + public enum OperationMode { + OPERATION_MODE_TEST_FAILURE(-1), + OPERATION_MODE_PRODUCTION(0), + OPERATION_MODE_TEST(1); + + final private int value; + OperationMode(int value) { + this.value = value; + } + public int getValue() { + return value; + } + } + // ======================================================================== +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperListenerManager.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperListenerManager.java new file mode 100644 index 000000000..f4a827f65 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperListenerManager.java @@ -0,0 +1,102 @@ +package com.samsung.android.sdk.iap.lib.helper; + +import com.samsung.android.sdk.iap.lib.helper.task.ConsumePurchasedItemsTask; +import com.samsung.android.sdk.iap.lib.helper.task.GetOwnedListTask; +import com.samsung.android.sdk.iap.lib.helper.task.GetProductsDetailsTask; +import com.samsung.android.sdk.iap.lib.listener.OnConsumePurchasedItemsListener; +import com.samsung.android.sdk.iap.lib.listener.OnGetOwnedListListener; +import com.samsung.android.sdk.iap.lib.listener.OnGetProductsDetailsListener; +import com.samsung.android.sdk.iap.lib.listener.OnPaymentListener; + +/** + * Created by sangbum7.kim on 2017-08-29. + */ + +public class HelperListenerManager { + private static HelperListenerManager mInstance = null; + + private OnGetProductsDetailsListener mOnGetProductsDetailsListener = null; + private OnGetOwnedListListener mOnGetOwnedListListener = null; + private OnConsumePurchasedItemsListener mOnConsumePurchasedItemsListener = null; + private OnPaymentListener mOnPaymentListener = null; + + /** + * HelperListenerManager singleton reference method + */ + public static HelperListenerManager getInstance() { + if (mInstance == null) { + mInstance = new HelperListenerManager(); + } + return mInstance; + } + + public static void destroy() { + mInstance = null; + } + + /** + * HelperListenerManager constructor + */ + private HelperListenerManager() { + mOnGetProductsDetailsListener = null; + mOnGetOwnedListListener = null; + mOnConsumePurchasedItemsListener = null; + mOnPaymentListener = null; + } + + /** + * Register {@link OnGetProductsDetailsListener} callback interface to be invoked when {@link GetProductsDetailsTask} has been finished. + * + * @param _onGetProductsDetailsListener + */ + public void setOnGetProductsDetailsListener(OnGetProductsDetailsListener _onGetProductsDetailsListener) { + mOnGetProductsDetailsListener = _onGetProductsDetailsListener; + } + + public OnGetProductsDetailsListener getOnGetProductsDetailsListener() { + return mOnGetProductsDetailsListener; + } + + + /** + * Register {@link OnGetOwnedListListener} callback interface to be invoked when {@link GetOwnedListTask} has been finished. + * + * @param _onGetOwnedListListener + */ + public void setOnGetOwnedListListener(OnGetOwnedListListener _onGetOwnedListListener) { + mOnGetOwnedListListener = _onGetOwnedListListener; + } + + public OnGetOwnedListListener getOnGetOwnedListListener() { + return mOnGetOwnedListListener; + } + + + /** + * Register {@link OnConsumePurchasedItemsListener} callback interface to be invoked when {@link ConsumePurchasedItemsTask} has been finished. + * + * @param _onConsumePurchasedItemsListener + */ + public void setOnConsumePurchasedItemsListener(OnConsumePurchasedItemsListener _onConsumePurchasedItemsListener) { + mOnConsumePurchasedItemsListener = _onConsumePurchasedItemsListener; + } + + public OnConsumePurchasedItemsListener getOnConsumePurchasedItemsListener() { + return mOnConsumePurchasedItemsListener; + } + + + /** + * Register a callback interface to be invoked when Purchase Process has been finished. + * + * @param _onPaymentListener + */ + public void setOnPaymentListener(OnPaymentListener _onPaymentListener) { + mOnPaymentListener = _onPaymentListener; + } + + + public OnPaymentListener getOnPaymentListener() { + return mOnPaymentListener; + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperUtil.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperUtil.java new file mode 100644 index 000000000..265ff6f50 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/HelperUtil.java @@ -0,0 +1,335 @@ +package com.samsung.android.sdk.iap.lib.helper; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.Signature; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.text.Html; +import android.util.Log; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.activity.BaseActivity; +import com.samsung.android.sdk.iap.lib.dialog.BaseDialogFragment; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; + +/** + * Created by sangbum7.kim on 2017-08-17. + */ + +public class HelperUtil { + private static final String TAG = HelperUtil.class.getSimpleName(); + + /** + * show a dialog + * + * @param activity The activity adding the fragment that displays a dialog + * @param title The title to display + * @param message The message to display + * @param positiveListener The listener to be invoked when the positive button of the dialog is pressed + * @param negativeListener The listener to be invoked when the negative button of the dialog is pressed + */ + public static void showIapErrorDialog( + final Activity activity, + String title, + String message, + final BaseDialogFragment.OnClickListener positiveListener, + final BaseDialogFragment.OnClickListener negativeListener) { + showIapErrorDialog(activity, title, message, "", positiveListener, negativeListener); + } + + /** + * show a dialog + * + * @param activity The activity adding the fragment that displays a dialog + * @param title The title to display + * @param message The message to display + * @param messageExtra The extra message to display + * @param positiveListener The listener to be invoked when the positive button of the dialog is pressed + * @param negativeListener The listener to be invoked when the negative button of the dialog is pressed + */ + public static void showIapErrorDialog( + final Activity activity, + String title, + String message, + String messageExtra, + final BaseDialogFragment.OnClickListener positiveListener, + final BaseDialogFragment.OnClickListener negativeListener) { + new BaseDialogFragment() + .setDialogTitle(title) + .setDialogMessageText(message) + .setDialogMessageExtra(messageExtra) + .setDialogPositiveButton(activity.getString(android.R.string.ok), positiveListener) + .setDialogNegativeButton(activity.getString(android.R.string.cancel), negativeListener) + .show(activity.getFragmentManager(), BaseDialogFragment.IAP_DIALOG_TAG); + } + + /** + * show a dialog to update the Galaxy Store + * + * @param activity The activity adding the fragment that displays a dialog + */ + public static void showUpdateGalaxyStoreDialog(final Activity activity) { + // TODO: both title and message will be changed as UX Guide + new BaseDialogFragment() + .setDialogTitle(activity.getString(R.string.dream_ph_pheader_couldnt_complete_purchase)) + .setDialogMessageText(activity.getString( + R.string.dream_ph_body_to_complete_this_purchase_you_need_to_update_the_galaxy_store)) + .setDialogPositiveButton( + activity.getString(android.R.string.ok), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + goGalaxyStoreDetailPage(activity.getApplicationContext()); + activity.finish(); + } + }) + .setDialogNegativeButton( + activity.getString(android.R.string.cancel), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + activity.finish(); + } + }) + .show(activity.getFragmentManager(), BaseDialogFragment.IAP_DIALOG_TAG); + } + + /** + * show a dialog to enable the Galaxy Store + * + * @param activity The activity adding the fragment that displays a dialog + */ + public static void showEnableGalaxyStoreDialog(final Activity activity) { + // TODO: both title and message will be changed as UX Guide + new BaseDialogFragment() + .setDialogTitle(activity.getString(R.string.dream_ph_pheader_couldnt_complete_purchase)) + .setDialogMessageText( + activity.getString(R.string.dream_ph_body_to_complete_this_purchase_you_need_to_enable_the_galaxy_store_in_settings)) + .setDialogPositiveButton( + activity.getString(android.R.string.ok), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + HelperDefine.GALAXY_PACKAGE_NAME)); + activity.startActivityForResult(intent, HelperDefine.REQUEST_CODE_IS_ENABLE_APPS); + + activity.finish(); + } + }) + .setDialogNegativeButton( + activity.getString(android.R.string.cancel), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + activity.finish(); + } + }) + .show(activity.getFragmentManager(), BaseDialogFragment.IAP_DIALOG_TAG); + } + + /** + * show a dialog to notice that the Galaxy Store is invalid + * + * @param activity The activity adding the fragment that displays a dialog + */ + public static void showInvalidGalaxyStoreDialog(final Activity activity) { + final String ERROR_ISSUER_IAP_CLIENT = "IC"; + final int ERROR_CODE_INVALID_GALAXY_STORE = 10002; + + String source = String.format( + activity.getString( + R.string.dream_ph_body_contact_p1sscustomer_servicep2ss_for_more_information_n_nerror_code_c_p3ss), + "", "", + ERROR_ISSUER_IAP_CLIENT + ERROR_CODE_INVALID_GALAXY_STORE); + + CharSequence errorMessage; + // fromHtml(String) was deprecated in N OS + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + errorMessage = Html.fromHtml(source); + } else { + errorMessage = Html.fromHtml(source, Html.FROM_HTML_MODE_LEGACY); + } + new BaseDialogFragment() + .setDialogTitle(activity.getString(R.string.dream_ph_pheader_couldnt_complete_purchase)) + .setDialogMessageText(errorMessage) + .setDialogMessageExtra(ERROR_ISSUER_IAP_CLIENT + ERROR_CODE_INVALID_GALAXY_STORE) + .setDialogPositiveButton( + activity.getString(android.R.string.ok), + new BaseDialogFragment.OnClickListener() { + @Override + public void onClick() { + activity.finish(); + } + }) + .show(activity.getFragmentManager(), BaseDialogFragment.IAP_DIALOG_TAG); + } + + private static void goGalaxyStoreDetailPage(Context context) { + // Link of Galaxy Store for IAP install + // ------------------------------------------------------------ + Uri appsDeepLink = Uri.parse("samsungapps://StoreVersionInfo/"); + // ------------------------------------------------------------ + + Intent intent = new Intent(); + intent.setData(appsDeepLink); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_CLEAR_TOP | + Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + } else { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_CLEAR_TOP); + } + + if (intent.resolveActivity(context.getPackageManager()) != null) { + context.startActivity(intent); + } + } + + /** + * Check that Galaxy Store is installed + * + * @param _context Context + * @return If it is true Galaxy Store is installed. otherwise, not installed. + */ + static public boolean isInstalledAppsPackage(Context _context) { + PackageManager pm = _context.getPackageManager(); + try { + PackageInfo packageInfo = pm.getPackageInfo(HelperDefine.GALAXY_PACKAGE_NAME, PackageManager.GET_META_DATA); + int versionType = packageInfo.versionCode / 100000000; + Log.i(TAG, "isInstalledAppsPackage : " + packageInfo.versionCode + ", " + versionType); + switch (versionType) { + case 4: { + return packageInfo.versionCode >= HelperDefine.APPS_PACKAGE_VERSION; + } + case 5: { + return true; +// return packageInfo.versionCode >= HelperDefine.APPS_PACKAGE_VERSION_GO; + } + case 6: { + return packageInfo.versionCode >= HelperDefine.APPS_PACKAGE_VERSION_INDIA; + } + // Unverified version + default: + return true; + } + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + static public boolean isEnabledAppsPackage(Context context) { + //// TODO: 2017-08-16 Make sure the status is normal + int status = context.getPackageManager().getApplicationEnabledSetting(HelperDefine.GALAXY_PACKAGE_NAME); + Log.i(TAG, "isEnabledAppsPackage: status " + status); + return !((status == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) || (status == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)); + } + + + /** + * check validation of installed Galaxy Store in your device + * + * @param _context + * @return If it is true Galaxy Store is valid. otherwise, is not valid. + */ + static public boolean isValidAppsPackage(Context _context) { + boolean result = true; + try { + Signature[] sigs = _context.getPackageManager().getPackageInfo( + HelperDefine.GALAXY_PACKAGE_NAME, + PackageManager.GET_SIGNATURES).signatures; + if (sigs[0].hashCode() != HelperDefine.APPS_SIGNATURE_HASHCODE) { + result = false; + } + } catch (Exception e) { + e.printStackTrace(); + result = false; + } + + return result; + } + + /** + * SamsungAccount authentication + * + * @param _activity + */ + static public boolean startAccountActivity(final Activity _activity) { + ComponentName com = new ComponentName(HelperDefine.GALAXY_PACKAGE_NAME, + HelperDefine.IAP_PACKAGE_NAME + ".activity.AccountActivity"); + Context context = _activity.getApplicationContext(); + + Intent intent = new Intent(); + intent.setComponent(com); + + if (intent.resolveActivity(context.getPackageManager()) != null) { + _activity.startActivityForResult(intent, + HelperDefine.REQUEST_CODE_IS_ACCOUNT_CERTIFICATION); + return true; + } + return false; + } + + /** + * go to about page of Galaxy Store in order to install IAP package. + */ + static public void installAppsPackage(final BaseActivity _activity) { + // Set error in order to notify result to third-party application. + // ==================================================================== + ErrorVo errorVo = new ErrorVo(); + _activity.setErrorVo(errorVo); + + errorVo.setError( + HelperDefine.IAP_PAYMENT_IS_CANCELED, + _activity.getString(R.string.mids_sapps_pop_payment_canceled)); + // ==================================================================== + + // Show information dialog + // ==================================================================== + showUpdateGalaxyStoreDialog(_activity); + // ==================================================================== + } + + static public int checkAppsPackage(Context _context) { + // 1. If Galaxy Store is installed + // ==================================================================== + if (HelperUtil.isInstalledAppsPackage(_context)) { + // 1) If Galaxy Store is enabled + // ================================================================ + if (!HelperUtil.isEnabledAppsPackage(_context)) { + return HelperDefine.DIALOG_TYPE_DISABLE_APPLICATION; + // ================================================================ + // 2) If Galaxy Store is valid + // ================================================================ + } else if (HelperUtil.isValidAppsPackage(_context)) { + return HelperDefine.DIALOG_TYPE_NONE; + } else { + // ------------------------------------------------------------ + // show alert dialog if Galaxy Store is invalid + // ------------------------------------------------------------ + return HelperDefine.DIALOG_TYPE_INVALID_PACKAGE; + // ------------------------------------------------------------ + } + // ================================================================ + + // ==================================================================== + // 2. If Galaxy Store is not installed + // ==================================================================== + } else { + // When user click the OK button on the dialog, + // go to Galaxy Store Detail page + // ==================================================================== + return HelperDefine.DIALOG_TYPE_APPS_DETAIL; + } + // ==================================================================== + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/IapHelper.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/IapHelper.java new file mode 100644 index 000000000..7e5ad8a55 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/IapHelper.java @@ -0,0 +1,642 @@ +package com.samsung.android.sdk.iap.lib.helper; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.AsyncTask.Status; +import android.os.IBinder; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import com.samsung.android.iap.IAPConnector; +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.activity.CheckPackageActivity; +import com.samsung.android.sdk.iap.lib.activity.PaymentActivity; +import com.samsung.android.sdk.iap.lib.helper.task.ConsumePurchasedItemsTask; +import com.samsung.android.sdk.iap.lib.helper.task.GetOwnedListTask; +import com.samsung.android.sdk.iap.lib.helper.task.GetProductsDetailsTask; +import com.samsung.android.sdk.iap.lib.listener.OnConsumePurchasedItemsListener; +import com.samsung.android.sdk.iap.lib.listener.OnGetOwnedListListener; +import com.samsung.android.sdk.iap.lib.listener.OnGetProductsDetailsListener; +import com.samsung.android.sdk.iap.lib.listener.OnPaymentListener; +import com.samsung.android.sdk.iap.lib.service.BaseService; +import com.samsung.android.sdk.iap.lib.service.ConsumePurchasedItems; +import com.samsung.android.sdk.iap.lib.service.OwnedProduct; +import com.samsung.android.sdk.iap.lib.service.ProductsDetails; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; + +import java.util.ArrayList; + +public class IapHelper extends HelperDefine { + private static final String TAG = IapHelper.class.getSimpleName(); + + /** + * When you release a application, this Mode must be set to {@link HelperDefine.OperationMode.OPERATION_MODE_PRODUCTION} + * Please double-check this mode before release. + */ + private int mMode = HelperDefine.OperationMode.OPERATION_MODE_PRODUCTION.getValue(); + // ======================================================================== + + private Context mContext = null; + + private IAPConnector mIapConnector = null; + private ServiceConnection mServiceConn = null; + + // AsyncTask for API + // ======================================================================== + private GetProductsDetailsTask mGetProductsDetailsTask = null; + private GetOwnedListTask mGetOwnedListTask = null; + private ConsumePurchasedItemsTask mConsumePurchasedItemsTask = null; + // ======================================================================== + + private ArrayList mServiceQueue = new ArrayList(); + private BaseService mCurrentService = null; + + // API listener + private HelperListenerManager mListenerInstance = null; + + private static IapHelper mInstance = null; + + // State of IAP Service + // ======================================================================== + private int mState = HelperDefine.STATE_TERM; + private final static Object mOperationLock = new Object(); + static boolean mOperationRunningFlag = false; + private boolean mShowErrorDialog = true; + + // ######################################################################## + // ######################################################################## + // 1. SamsungIAPHeler object create and reference + // ######################################################################## + // ######################################################################## + + /** + * IapHelper constructor + * + * @param _context + */ + private IapHelper(Context _context) { + _setContextAndMode(_context); + _setListenerInstance(); + } + + /** + * IapHelper singleton reference method + * + * @param _context Context + */ + public static IapHelper getInstance(Context _context) { + Log.i(TAG, "IAP Helper version : " + HelperDefine.HELPER_VERSION); + if (null == mInstance) { + mInstance = new IapHelper(_context); + } else { + mInstance._setContextAndMode(_context); + } + + return mInstance; + } + + public void setOperationMode(OperationMode _mode) { + mMode = _mode.getValue(); + } + + private void _setContextAndMode(Context _context) { + mContext = _context.getApplicationContext(); + } + + private void _setListenerInstance() { + if (mListenerInstance != null) { + mListenerInstance.destroy(); + mListenerInstance = null; + } + mListenerInstance = HelperListenerManager.getInstance(); + } + + + // ######################################################################## + // ######################################################################## + // 2. Binding for IAPService + // ######################################################################## + // ######################################################################## + + /** + * bind to IAPService + */ + public void bindIapService() { + Log.i(TAG, "bindIapService()"); + // exit If already bound + // ==================================================================== + if (mState >= HelperDefine.STATE_BINDING) { + onBindIapFinished(HelperDefine.IAP_RESPONSE_RESULT_OK); + return; + } + // ==================================================================== + + // Connection to IAP service + // ==================================================================== + mServiceConn = new ServiceConnection() { + @Override + public void onServiceDisconnected(ComponentName _name) { + Log.i(TAG, "IAP Service Disconnected..."); + + mState = HelperDefine.STATE_TERM; + mIapConnector = null; + mServiceConn = null; + } + + @Override + public void onServiceConnected + ( + ComponentName _name, + IBinder _service + ) { + Log.i(TAG, "IAP Service Connected..."); + mIapConnector = IAPConnector.Stub.asInterface(_service); + + if (mIapConnector != null) { + mState = HelperDefine.STATE_BINDING; + onBindIapFinished(HelperDefine.IAP_RESPONSE_RESULT_OK); + } else { + mState = HelperDefine.STATE_TERM; + onBindIapFinished(HelperDefine.IAP_RESPONSE_RESULT_UNAVAILABLE); + } + } + }; + // ==================================================================== + Intent serviceIntent = new Intent(); + serviceIntent.setComponent(new ComponentName(HelperDefine.GALAXY_PACKAGE_NAME, HelperDefine.IAP_SERVICE_NAME)); + + // bind to IAPService + // ==================================================================== + try { + if (mContext == null || mContext.bindService(serviceIntent, + mServiceConn, + Context.BIND_AUTO_CREATE) == false) { + mState = HelperDefine.STATE_TERM; + onBindIapFinished(HelperDefine.IAP_RESPONSE_RESULT_UNAVAILABLE); + } + } catch (SecurityException e) { + Log.e(TAG, "SecurityException : " + e); + onBindIapFinished(HelperDefine.IAP_RESPONSE_RESULT_UNAVAILABLE); + } + // ==================================================================== + } + + + protected void onBindIapFinished(int _result) { + Log.i(TAG, "onBindIapFinished"); + if (_result == HelperDefine.IAP_RESPONSE_RESULT_OK) { + if (getServiceProcess() != null) { + getServiceProcess().runServiceProcess(); + } + } + // ============================================================ + // 2) If IAPService is not bound. + // ============================================================ + else { + if (getServiceProcess() != null) { + ErrorVo errorVo = new ErrorVo(); + errorVo.setError(HelperDefine.IAP_ERROR_INITIALIZATION, + mContext.getString(R.string.mids_sapps_pop_unknown_error_occurred) + "[Lib_Bind]"); + errorVo.setShowDialog(mShowErrorDialog); + getServiceProcess().setErrorVo(errorVo); + getServiceProcess().onEndProcess(); + } + } + } + + + /* ######################################################################## + * ######################################################################## + * 3. IAP APIs. + * ######################################################################## + * ##################################################################### */ + /////////////////////////////////////////////////////////////////////////// + // 3.1) getProductsDetails /////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + /** + *
+     * This load item list by starting productActivity in this library, and the result will be sent to {@link OnGetProductsDetailsListener} Callback
+     * interface.
+     *
+     * 
+ * + * @param _productIds + * @param _onGetProductsDetailsListener + */ + public void getProductsDetails + ( + String _productIds, + OnGetProductsDetailsListener _onGetProductsDetailsListener + ) { + try { + if (_onGetProductsDetailsListener == null) { + throw new Exception("_onGetProductsDetailsListener is null"); + } + + ProductsDetails productsDetails = new ProductsDetails(mInstance, mContext, _onGetProductsDetailsListener); + productsDetails.setProductId(_productIds); + setServiceProcess(productsDetails); + + IapStartInProgressFlag(); + checkAppsPackage(); + } catch (IapInProgressException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * execute GetProductsDetailsTask + */ + public boolean safeGetProductsDetails + ( + ProductsDetails _baseService, + String _productIDs, + boolean _showErrorDialog + ) { + try { + if (mGetProductsDetailsTask != null && + mGetProductsDetailsTask.getStatus() != Status.FINISHED) { + mGetProductsDetailsTask.cancel(true); + } + if (mIapConnector == null || mContext == null) { + return false; + } else { + mGetProductsDetailsTask = new GetProductsDetailsTask(_baseService, + mIapConnector, + mContext, + _productIDs, + _showErrorDialog, + mMode); + mGetProductsDetailsTask.execute(); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + + /////////////////////////////////////////////////////////////////////////// + // 3.2) getOwnedList ////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + /** + *
+     * This load owned product list by starting OwnedListActivity in this library, and the result will be sent to {@link OnGetOwnedListListener}
+     * Callback interface.
+     *
+     * 
+ * + * @param _productType + * @param _onGetOwnedListListener + */ + public boolean getOwnedList + ( + String _productType, + OnGetOwnedListListener _onGetOwnedListListener + ) { + Log.i(TAG, "getOwnedList"); + try { + if (_onGetOwnedListListener == null) { + throw new Exception("_onGetOwnedListListener is null"); + } + if (TextUtils.isEmpty(_productType)) { + throw new Exception("_productType is null or empty"); + } + + OwnedProduct ownedProduct = new OwnedProduct(mInstance, mContext, _onGetOwnedListListener); + ownedProduct.setProductType(_productType); + setServiceProcess(ownedProduct); + + IapStartInProgressFlag(); + checkAppsPackage(); + } catch (IapInProgressException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * execute GetOwnedListTask + */ + public boolean safeGetOwnedList + ( + OwnedProduct _baseService, + String _productType, + boolean _showErrorDialog + ) { + try { + if (mGetOwnedListTask != null && + mGetOwnedListTask.getStatus() != Status.FINISHED) { + mGetOwnedListTask.cancel(true); + } + + if (mIapConnector == null || mContext == null) { + return false; + } else { + mGetOwnedListTask = new GetOwnedListTask(_baseService, + mIapConnector, + mContext, + _productType, + _showErrorDialog, + mMode); + + mGetOwnedListTask.execute(); + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /////////////////////////////////////////////////////////////////////////// + // 3.3) consumePurchasedItems ///////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + /** + *
+     * This load item list by starting OwnedListActivity in this library, and the result will be sent to {@link OnConsumePurchasedItemsListener}
+     * Callback interface.
+     *
+     * 
+ * + * @param _purchaseIds + * @param _onConsumePurchasedItemsListener + */ + public boolean consumePurchasedItems + ( + String _purchaseIds, + OnConsumePurchasedItemsListener _onConsumePurchasedItemsListener + ) { + try { + if (_onConsumePurchasedItemsListener == null) { + throw new Exception("_onConsumePurchasedItemsListener is null"); + } + if (TextUtils.isEmpty(_purchaseIds)) { + throw new Exception("_purchaseIds is null or empty"); + } + + ConsumePurchasedItems consumePurchasedItems = new ConsumePurchasedItems(mInstance, mContext, _onConsumePurchasedItemsListener); + consumePurchasedItems.setPurchaseIds(_purchaseIds); + setServiceProcess(consumePurchasedItems); + + IapStartInProgressFlag(); + checkAppsPackage(); + } catch (IapInProgressException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + * execute ConsumePurchasedItemsTask + */ + public boolean safeConsumePurchasedItems + ( + ConsumePurchasedItems _baseService, + String _purchaseIds, + boolean _showErrorDialog + ) { + try { + if (mConsumePurchasedItemsTask != null && + mConsumePurchasedItemsTask.getStatus() != Status.FINISHED) { + mConsumePurchasedItemsTask.cancel(true); + } + + mConsumePurchasedItemsTask = new ConsumePurchasedItemsTask(_baseService, + mIapConnector, + mContext, + _purchaseIds, + _showErrorDialog, + mMode); + mConsumePurchasedItemsTask.execute(); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + /////////////////////////////////////////////////////////////////////////// + // 3.4) startPurchase / /////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// + + /** + *
+     * Start payment process by starting {@link PaymentActivity} in this library, and result will be sent to {@link OnPaymentListener} interface. To
+     * do that, PaymentActivity must be described in AndroidManifest.xml of third-party application as below.
+     * 

+ * <activity android:name="com.sec.android.iap.lib.activity.PaymentActivity" android:theme="@style/Theme.Empty" + * android:configChanges="orientation|screenSize"/> + *

+ * + * @param _itemId + * @param _passThroughParam + * @param _onPaymentListener + */ + public boolean startPayment + ( + String _itemId, + String _passThroughParam, + OnPaymentListener _onPaymentListener + ) { + try { + if (_onPaymentListener == null) { + throw new Exception("OnPaymentListener is null"); + } + if (TextUtils.isEmpty(_itemId)) { + throw new Exception("_itemId is null or empty"); + } + if (_passThroughParam != null && _passThroughParam.getBytes("UTF-8").length > HelperDefine.PASSTHROGUH_MAX_LENGTH) { + throw new Exception("PassThroughParam length exceeded (MAX " + HelperDefine.PASSTHROGUH_MAX_LENGTH + ")"); + } + + IapStartInProgressFlag(); + mListenerInstance.setOnPaymentListener(_onPaymentListener); + + Intent intent = new Intent(mContext, PaymentActivity.class); + intent.putExtra("ItemId", _itemId); + String encodedPassThroughParam = ""; + if (_passThroughParam != null) { + encodedPassThroughParam = Base64.encodeToString(_passThroughParam.getBytes("UTF-8"), 0); + } + intent.putExtra("PassThroughParam", encodedPassThroughParam); + intent.putExtra("ShowErrorDialog", mShowErrorDialog); + intent.putExtra("OperationMode", mMode); + Log.i(TAG, "startPayment: " + mMode); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + mContext.startActivity(intent); + } catch (IapInProgressException e) { + e.printStackTrace(); + return false; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + + /** + *
+     * Start payment process by starting {@link PaymentActivity} in this library, and result will be sent to {@link OnPaymentListener} interface. To
+     * do that, PaymentActivity must be described in AndroidManifest.xml of third-party application as below.
+     * 

+ * <activity android:name="com.sec.android.iap.lib.activity.PaymentActivity" android:theme="@style/Theme.Empty" + * android:configChanges="orientation|screenSize"/> + *

+ * + * @param _itemId + * @param _passThroughParam + * @param _showSuccessDialog Unused parameter. + * @param _onPaymentListener + * @deprecated + */ + public boolean startPayment + ( + String _itemId, + String _passThroughParam, + boolean _showSuccessDialog, + OnPaymentListener _onPaymentListener + ) { + return startPayment(_itemId, _passThroughParam, _onPaymentListener); + } + + // ######################################################################## + // ######################################################################## + // 4. etc + // ######################################################################## + // ######################################################################## + + /** + * Stop running task, {@link GetProductsDetailsTask}, {@link ConsumePurchasedItemsTask} or {@link GetOwnedListTask} } before dispose(). + */ + private void stopTasksIfNotFinished() { + if (mGetProductsDetailsTask != null) { + if (mGetProductsDetailsTask.getStatus() != Status.FINISHED) { + Log.e(TAG, "stopTasksIfNotFinished: mGetProductsDetailsTask Status > " + mGetProductsDetailsTask.getStatus()); + mGetProductsDetailsTask.cancel(true); + } + } + + if (mGetOwnedListTask != null) { + if (mGetOwnedListTask.getStatus() != Status.FINISHED) { + Log.e(TAG, "stopTasksIfNotFinished: mGetOwnedListTask Status > " + mGetOwnedListTask.getStatus()); + mGetOwnedListTask.cancel(true); + } + } + + if (mConsumePurchasedItemsTask != null) { + if (mConsumePurchasedItemsTask.getStatus() != Status.FINISHED) { + Log.e(TAG, "stopTasksIfNotFinished: mConsumePurchasedItemsTask Status > " + mConsumePurchasedItemsTask.getStatus()); + mConsumePurchasedItemsTask.cancel(true); + } + } + } + + /** + * Unbind from IAPService and release used resources. + */ + public void dispose() { + stopTasksIfNotFinished(); + + if (mContext != null && mServiceConn != null) { + mContext.unbindService(mServiceConn); + } + + mState = HelperDefine.STATE_TERM; + mServiceConn = null; + mIapConnector = null; + clearServiceProcess(); + IapEndInProgressFlag(); + } + + void IapStartInProgressFlag() throws IapInProgressException { + Log.i(TAG, "IapStartInProgressFlag"); + synchronized (mOperationLock) { + if (mOperationRunningFlag) { + throw new IapInProgressException("another operation is running"); + } + mOperationRunningFlag = true; + } + } + + void IapEndInProgressFlag() { + Log.i(TAG, "IapEndInProgressFlag"); + synchronized (mOperationLock) { + mOperationRunningFlag = false; + } + } + + protected static class IapInProgressException extends Exception { + public IapInProgressException(String message) { + super(message); + } + } + + void checkAppsPackage() { + int checkResult = HelperUtil.checkAppsPackage(mContext); + if (checkResult == HelperDefine.DIALOG_TYPE_NONE) { + bindIapService(); + } else { + Intent intent = new Intent(mContext, CheckPackageActivity.class); + intent.putExtra("DialogType", checkResult); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + } + } + + /** + * Sets whether error popup is displayed when payment is finished. + */ + public void setShowErrorDialog(boolean _showErrorDialog) { + this.mShowErrorDialog = _showErrorDialog; + } + + public boolean getShowErrorDialog() { + return this.mShowErrorDialog; + } + + public BaseService getServiceProcess() { + return getServiceProcess(false); + } + + public BaseService getServiceProcess(boolean _nextProcess) { + if (mCurrentService == null || _nextProcess) { + mCurrentService = null; + if (mServiceQueue.size() > 0) { + mCurrentService = mServiceQueue.get(0); + mServiceQueue.remove(0); + } + } + return mCurrentService; + } + + private void setServiceProcess(BaseService _baseService) { + mServiceQueue.add(_baseService); + } + + private void clearServiceProcess() { + do { + if (mCurrentService != null) { + mCurrentService.releaseProcess(); + } + mCurrentService = getServiceProcess(true); + } while (mCurrentService != null); + mServiceQueue.clear(); + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/BaseTask.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/BaseTask.java new file mode 100644 index 000000000..c284cef37 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/BaseTask.java @@ -0,0 +1,65 @@ +package com.samsung.android.sdk.iap.lib.helper.task; + +import android.content.Context; +import android.os.AsyncTask; +import android.util.Log; + +import com.samsung.android.iap.IAPConnector; +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.service.BaseService; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; + +/** + * Created by sangbum7.kim on 2017-09-01. + */ + +public class BaseTask extends AsyncTask { + private static final String TAG = BaseTask.class.getSimpleName(); + + protected BaseService mBaseService; + protected IAPConnector mIapConnector; + protected Context mContext; + protected int mMode; + protected String mPackageName = ""; + + protected ErrorVo mErrorVo = new ErrorVo(); + + public BaseTask(BaseService _baseService, + IAPConnector _iapConnector, + Context _context, + boolean _showErrorDialog, + int _mode) { + + mBaseService = _baseService; + mIapConnector = _iapConnector; + mContext = _context; + if (mContext != null) { + mPackageName = mContext.getPackageName(); + } + mMode = _mode; + mErrorVo.setShowDialog(_showErrorDialog); + mBaseService.setErrorVo(mErrorVo); + } + + @Override + protected Boolean doInBackground(String... params) { + return true; + } + + @Override + protected void onPostExecute(Boolean _result) { + // ================================================================ + if (!_result) { + mErrorVo.setError(mErrorVo.getErrorCode(), mContext.getString(R.string.mids_sapps_pop_unknown_error_occurred)); + } + // ================================================================ + + mBaseService.onEndProcess(); + } + + @Override + protected void onCancelled() { + Log.e(TAG, "onCancelled: task cancelled"); + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/ConsumePurchasedItemsTask.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/ConsumePurchasedItemsTask.java new file mode 100644 index 000000000..95b7776be --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/ConsumePurchasedItemsTask.java @@ -0,0 +1,105 @@ +package com.samsung.android.sdk.iap.lib.helper.task; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; + +import com.samsung.android.iap.IAPConnector; +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.service.ConsumePurchasedItems; +import com.samsung.android.sdk.iap.lib.vo.ConsumeVo; + +import java.util.ArrayList; + +/** + * Asynchronized Task to load a list of items + */ +public class ConsumePurchasedItemsTask extends BaseTask { + private static final String TAG = GetOwnedListTask.class.getSimpleName(); + private String mPurchaseIds = ""; + + ArrayList mConsumeList = new ArrayList(); + + public ConsumePurchasedItemsTask + ( + ConsumePurchasedItems _baseService, + IAPConnector _iapConnector, + Context _context, + String _purchaseIds, + boolean _showErrorDialog, + int _mode + ) { + super(_baseService, _iapConnector, _context, _showErrorDialog, _mode); + mPurchaseIds = _purchaseIds; + + _baseService.setConsumeList(mConsumeList); + } + + @Override + protected Boolean doInBackground(String... params) { + try { + // 1) call getItemList() method of IAPService + // ============================================================ + Bundle bundle = mIapConnector.consumePurchasedItems( + mPackageName, + mPurchaseIds, + mMode); + // ============================================================ + + // 2) save status code, error string and extra String. + // ============================================================ + if (bundle != null) { + mErrorVo.setError(bundle.getInt(HelperDefine.KEY_NAME_STATUS_CODE), + bundle.getString(HelperDefine.KEY_NAME_ERROR_STRING)); + } else { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + mContext.getString( + R.string.mids_sapps_pop_unknown_error_occurred)); + } + // ============================================================ + + // 3) If item list is loaded successfully, + // make item list by Bundle data + // ============================================================ + // ============================================================ + + // 3) If item list is loaded successfully, + // make item list by Bundle data + // ============================================================ + if (mErrorVo.getErrorCode() == HelperDefine.IAP_ERROR_NONE) { + if (bundle != null) { + ArrayList consumePurchasedItemsStringList = + bundle.getStringArrayList(HelperDefine.KEY_NAME_RESULT_LIST); + + if (consumePurchasedItemsStringList != null) { + for (String consumePurchasedItemString : consumePurchasedItemsStringList) { + ConsumeVo consumeVo = new ConsumeVo(consumePurchasedItemString); + mConsumeList.add(consumeVo); + } + } else { + Log.i(TAG, "Bundle Value 'RESULT_LIST' is null."); + } + } + } + // ============================================================ + // 4) If failed, print log. + // ============================================================ + else { + Log.e(TAG, mErrorVo.getErrorString()); + } + // ============================================================ + } catch (Exception e) { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + mContext.getString( + R.string.mids_sapps_pop_unknown_error_occurred)); + + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetOwnedListTask.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetOwnedListTask.java new file mode 100644 index 000000000..a52b7d21d --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetOwnedListTask.java @@ -0,0 +1,112 @@ +package com.samsung.android.sdk.iap.lib.helper.task; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; + +import com.samsung.android.iap.IAPConnector; +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.service.OwnedProduct; +import com.samsung.android.sdk.iap.lib.vo.OwnedProductVo; + +import java.util.ArrayList; + +/** + * Asynchronized Task to load a list of items + */ +public class GetOwnedListTask extends BaseTask { + private static final String TAG = GetOwnedListTask.class.getSimpleName(); + private String mProductType = ""; + ArrayList mOwnedList = new ArrayList(); + + public GetOwnedListTask + ( + OwnedProduct _baseService, + IAPConnector _iapConnector, + Context _context, + String _productType, + boolean _showErrorDialog, + int _mode + ) { + super(_baseService, _iapConnector, _context, _showErrorDialog, _mode); + mProductType = _productType; + _baseService.setOwnedList(mOwnedList); + } + + @Override + protected Boolean doInBackground(String... params) { + Log.i(TAG, "doInBackground: start"); + try { + int pagingIndex = 1; + do { + Log.i(TAG, "doInBackground: pagingIndex = " + pagingIndex); + // 1) call getItemList() method of IAPService + // ============================================================ + Bundle bundle = mIapConnector.getOwnedList( + mPackageName, + mProductType, + pagingIndex, + mMode); + // ============================================================ + + // 2) save status code, error string and extra String. + // ============================================================ + if (bundle != null) { + mErrorVo.setError(bundle.getInt(HelperDefine.KEY_NAME_STATUS_CODE), + bundle.getString(HelperDefine.KEY_NAME_ERROR_STRING)); + } else { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + mContext.getString( + R.string.mids_sapps_pop_unknown_error_occurred)); + } + // ============================================================ + + // 3) If item list is loaded successfully, + // make item list by Bundle data + // ============================================================ + if (mErrorVo.getErrorCode() == HelperDefine.IAP_ERROR_NONE) { + if (bundle != null) { + String nextPagingIndex = bundle.getString(HelperDefine.NEXT_PAGING_INDEX); + if (nextPagingIndex != null && nextPagingIndex.length() > 0) { + pagingIndex = Integer.parseInt(nextPagingIndex); + } else { + pagingIndex = -1; + } + + ArrayList ownedProductStringList = + bundle.getStringArrayList(HelperDefine.KEY_NAME_RESULT_LIST); + + if (ownedProductStringList != null) { + for (String ownedProductString : ownedProductStringList) { + OwnedProductVo ownedPrroductVo = new OwnedProductVo(ownedProductString); + mOwnedList.add(ownedPrroductVo); + } + } else { + Log.i(TAG, "Bundle Value 'RESULT_LIST' is null."); + } + } + } + // ============================================================ + // 4) If failed, print log. + // ============================================================ + else { + Log.e(TAG, mErrorVo.getErrorString()); + return true; + } + // ============================================================ + } while (pagingIndex > 0); + } catch (Exception e) { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + mContext.getString( + R.string.mids_sapps_pop_unknown_error_occurred)); + + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetProductsDetailsTask.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetProductsDetailsTask.java new file mode 100644 index 000000000..65002d7b0 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/helper/task/GetProductsDetailsTask.java @@ -0,0 +1,115 @@ +package com.samsung.android.sdk.iap.lib.helper.task; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; + +import com.samsung.android.iap.IAPConnector; +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.service.ProductsDetails; +import com.samsung.android.sdk.iap.lib.vo.ProductVo; + +import java.util.ArrayList; + +/** + * Asynchronized Task to load a list of items + */ +public class GetProductsDetailsTask extends BaseTask { + private static final String TAG = GetProductsDetailsTask.class.getSimpleName(); + private String mProductIds = ""; + ArrayList mProductsDetails = new ArrayList(); + + public GetProductsDetailsTask + ( + ProductsDetails _baseService, + IAPConnector _iapConnector, + Context _context, + String _productIDs, + boolean _showErrorDialog, + int _mode + ) { + super(_baseService, _iapConnector, _context, _showErrorDialog, _mode); + mProductIds = _productIDs; + + _baseService.setProductsDetails(mProductsDetails); + } + + @Override + protected Boolean doInBackground(String... params) { + try { + int pagingIndex = 1; + do { + // 1) call getProductsDetails() method of IAPService + // ---- Order Priority ---- + // 1. if productIds is not empty, the infomations abouts products included in the productIds are returned + // 2. if productIds is empty, the infomations about all products in this package are returned on a page by page + // ============================================================ + Bundle bundle = mIapConnector.getProductsDetails( + mPackageName, + mProductIds, + pagingIndex, + mMode); + // ============================================================ + + // 2) save status code, error string and extra String. + // ============================================================ + if (bundle != null) { + mErrorVo.setError(bundle.getInt(HelperDefine.KEY_NAME_STATUS_CODE), + bundle.getString(HelperDefine.KEY_NAME_ERROR_STRING)); + } else { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + mContext.getString( + R.string.mids_sapps_pop_unknown_error_occurred)); + } + // ============================================================ + + // 3) If item list is loaded successfully, + // make item list by Bundle data + // ============================================================ + if (mErrorVo.getErrorCode() == HelperDefine.IAP_ERROR_NONE) { + if (bundle != null) { + String nextPagingIndex = bundle.getString(HelperDefine.NEXT_PAGING_INDEX); + if (nextPagingIndex != null && nextPagingIndex.length() > 0) { + pagingIndex = Integer.parseInt(nextPagingIndex); + Log.i(TAG, "PagingIndex = " + nextPagingIndex); + } else { + pagingIndex = -1; + } + + ArrayList productStringList = + bundle.getStringArrayList(HelperDefine.KEY_NAME_RESULT_LIST); + + if (productStringList != null) { + for (String productString : productStringList) { + ProductVo productVo = new ProductVo(productString); + mProductsDetails.add(productVo); + } + } else { + Log.i(TAG, "Bundle Value 'RESULT_LIST' is null."); + } + } + } + // ============================================================ + // 4) If failed, print log. + // ============================================================ + else { + Log.e(TAG, mErrorVo.getErrorString()); + return true; + } + // ============================================================ + } while (pagingIndex > 0); + } catch (Exception e) { + mErrorVo.setError( + HelperDefine.IAP_ERROR_COMMON, + mContext.getString( + R.string.mids_sapps_pop_unknown_error_occurred)); + + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnConsumePurchasedItemsListener.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnConsumePurchasedItemsListener.java new file mode 100644 index 000000000..4311cde1b --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnConsumePurchasedItemsListener.java @@ -0,0 +1,20 @@ +package com.samsung.android.sdk.iap.lib.listener; + +import com.samsung.android.sdk.iap.lib.helper.task.GetOwnedListTask; +import com.samsung.android.sdk.iap.lib.vo.ConsumeVo; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; + +import java.util.ArrayList; + +/** + * Callback Interface used with {@link GetOwnedListTask} + */ +public interface OnConsumePurchasedItemsListener { + /** + * Callback method to be invoked when {@link GetOwnedListTask} has been finished. + * + * @param _errorVO + * @param _consumeList + */ + void onConsumePurchasedItems(ErrorVo _errorVO, ArrayList _consumeList); +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetOwnedListListener.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetOwnedListListener.java new file mode 100644 index 000000000..35d76f957 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetOwnedListListener.java @@ -0,0 +1,20 @@ +package com.samsung.android.sdk.iap.lib.listener; + +import com.samsung.android.sdk.iap.lib.helper.task.GetOwnedListTask; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; +import com.samsung.android.sdk.iap.lib.vo.OwnedProductVo; + +import java.util.ArrayList; + +/** + * Callback Interface used with {@link GetOwnedListTask} + */ +public interface OnGetOwnedListListener { + /** + * Callback method to be invoked when {@link GetOwnedListTask} has been finished. + * + * @param _errorVO + * @param _ownedList + */ + void onGetOwnedProducts(ErrorVo _errorVO, ArrayList _ownedList); +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetProductsDetailsListener.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetProductsDetailsListener.java new file mode 100644 index 000000000..55442b181 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnGetProductsDetailsListener.java @@ -0,0 +1,20 @@ +package com.samsung.android.sdk.iap.lib.listener; + +import com.samsung.android.sdk.iap.lib.helper.task.GetProductsDetailsTask; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; +import com.samsung.android.sdk.iap.lib.vo.ProductVo; + +import java.util.ArrayList; + +/** + * Callback Interface used with {@link GetProductsDetailsTask} + */ +public interface OnGetProductsDetailsListener { + /** + * Callback method to be invoked when {@link GetProductsDetailsTask} has been finished. + * + * @param _errorVO + * @param _productList + */ + void onGetProducts(ErrorVo _errorVO, ArrayList _productList); +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnIapBindListener.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnIapBindListener.java new file mode 100644 index 000000000..ff6ca117c --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnIapBindListener.java @@ -0,0 +1,13 @@ +package com.samsung.android.sdk.iap.lib.listener; + +/** + * Callback Interface to be invoked when bind to IAPService has been finished. + */ +public interface OnIapBindListener { + /** + * Callback method to be invoked after binding to IAP service successfully. + * + * @param result + */ + public void onBindIapFinished(int result); +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnPaymentListener.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnPaymentListener.java new file mode 100644 index 000000000..00a098365 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnPaymentListener.java @@ -0,0 +1,15 @@ +package com.samsung.android.sdk.iap.lib.listener; + +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; +import com.samsung.android.sdk.iap.lib.vo.PurchaseVo; + +/** + * Callback Interface to be invoked when payment has been finished. + */ +public interface OnPaymentListener { + /** + * Callback method to be invoked when payment has been finished. There is return data for result of financial transaction whenever it was + * successful or failed. + */ + void onPayment(ErrorVo _errorVO, PurchaseVo _purchaseVO); +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnSucceedBind.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnSucceedBind.java new file mode 100644 index 000000000..3db6ffc21 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/listener/OnSucceedBind.java @@ -0,0 +1,8 @@ +package com.samsung.android.sdk.iap.lib.listener; + +/** + * Created by sangbum7.kim on 2018-02-28. + */ + +public interface OnSucceedBind { +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/BaseService.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/BaseService.java new file mode 100644 index 000000000..d6b03eb1e --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/BaseService.java @@ -0,0 +1,76 @@ +package com.samsung.android.sdk.iap.lib.service; + +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.activity.AccountActivity; +import com.samsung.android.sdk.iap.lib.activity.DialogActivity; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; +import com.samsung.android.sdk.iap.lib.vo.ErrorVo; + +/** + * Created by sangbum7.kim on 2018-02-28. + */ + +public abstract class BaseService { + private static final String TAG = BaseService.class.getSimpleName(); + + protected ErrorVo mErrorVo = new ErrorVo(); + protected IapHelper mIapHelper = null; + protected Context mContext = null; + + public BaseService(IapHelper _iapHelper, Context _context) { + mIapHelper = _iapHelper; + mContext = _context; + mErrorVo.setError(HelperDefine.IAP_ERROR_INITIALIZATION, mContext.getString(R.string.mids_sapps_pop_unknown_error_occurred)); + } + + public ErrorVo getErrorVo() { + return mErrorVo; + } + + public void setErrorVo(ErrorVo mErrorVo) { + this.mErrorVo = mErrorVo; + } + + public abstract void runServiceProcess(); + + public void onEndProcess() { + Log.i(TAG, "BaseService.onEndProcess"); + + if (mErrorVo.getErrorCode() == HelperDefine.IAP_ERROR_NEED_SA_LOGIN) { + Intent intent = new Intent(mContext, AccountActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + return; + } else if (mErrorVo.getErrorCode() != HelperDefine.IAP_ERROR_NONE) { + if (mErrorVo.getErrorCode() != HelperDefine.IAP_ERROR_NETWORK_NOT_AVAILABLE && mErrorVo.isShowDialog()) { + Intent intent = new Intent(mContext, DialogActivity.class); + intent.putExtra("Title", mContext.getString(R.string.dream_ph_pheader_couldnt_complete_purchase)); + intent.putExtra("Message", mErrorVo.getErrorString()); + intent.putExtra("DialogType", HelperDefine.DIALOG_TYPE_NOTIFICATION); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + } + } + + if (mIapHelper != null) { + BaseService baseService = mIapHelper.getServiceProcess(true); + if (baseService != null) { + baseService.runServiceProcess(); + } else { + mIapHelper.dispose(); + } + } + onReleaseProcess(); + } + + public void releaseProcess() { + onReleaseProcess(); + } + + abstract void onReleaseProcess(); +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ConsumePurchasedItems.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ConsumePurchasedItems.java new file mode 100644 index 000000000..3766b4a25 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ConsumePurchasedItems.java @@ -0,0 +1,62 @@ +package com.samsung.android.sdk.iap.lib.service; + +import android.content.Context; +import android.util.Log; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; +import com.samsung.android.sdk.iap.lib.listener.OnConsumePurchasedItemsListener; +import com.samsung.android.sdk.iap.lib.vo.ConsumeVo; + +import java.util.ArrayList; + +/** + * Created by sangbum7.kim on 2018-02-28. + */ + +public class ConsumePurchasedItems extends BaseService { + private static final String TAG = ConsumePurchasedItems.class.getSimpleName(); + + private OnConsumePurchasedItemsListener mOnConsumePurchasedItemsListener = null; + private static String mPurchaseIds = ""; + protected ArrayList mConsumeList = null; + + public ConsumePurchasedItems(IapHelper _iapHelper, Context _context, OnConsumePurchasedItemsListener _onConsumePurchasedItemsListener) { + super(_iapHelper, _context); + mOnConsumePurchasedItemsListener = _onConsumePurchasedItemsListener; + } + + public static void setPurchaseIds(String _purchaseIds) { + mPurchaseIds = _purchaseIds; + } + + public void setConsumeList(ArrayList _consumeList) { + this.mConsumeList = _consumeList; + } + + @Override + public void runServiceProcess() { + if (mIapHelper != null) { + if (mIapHelper.safeConsumePurchasedItems(ConsumePurchasedItems.this, + mPurchaseIds, + mIapHelper.getShowErrorDialog()) == true) { + return; + } + } + mErrorVo.setError(HelperDefine.IAP_ERROR_INITIALIZATION, mContext.getString(R.string.mids_sapps_pop_unknown_error_occurred)); + onEndProcess(); + } + + @Override + public void onReleaseProcess() { + Log.i(TAG, "ConsumePurchasedItems.onReleaseProcess"); + try { + if (mOnConsumePurchasedItemsListener != null) { + mOnConsumePurchasedItemsListener.onConsumePurchasedItems(mErrorVo, mConsumeList); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/OwnedProduct.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/OwnedProduct.java new file mode 100644 index 000000000..ac3dd40f0 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/OwnedProduct.java @@ -0,0 +1,63 @@ +package com.samsung.android.sdk.iap.lib.service; + +import android.content.Context; +import android.util.Log; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; +import com.samsung.android.sdk.iap.lib.listener.OnGetOwnedListListener; +import com.samsung.android.sdk.iap.lib.vo.OwnedProductVo; + +import java.util.ArrayList; + +/** + * Created by sangbum7.kim on 2018-02-28. + */ + +public class OwnedProduct extends BaseService { + private static final String TAG = OwnedProduct.class.getSimpleName(); + + private OnGetOwnedListListener mOnGetOwnedListListener = null; + private static String mProductType = ""; + protected ArrayList mOwnedList = null; + + public OwnedProduct(IapHelper _iapHelper, Context _context, OnGetOwnedListListener _onGetOwnedListListener) { + super(_iapHelper, _context); + mOnGetOwnedListListener = _onGetOwnedListListener; + } + + public static void setProductType(String _productType) { + mProductType = _productType; + } + + public void setOwnedList(ArrayList _ownedList) { + this.mOwnedList = _ownedList; + } + + @Override + public void runServiceProcess() { + Log.i(TAG, "runServiceProcess"); + if (mIapHelper != null) { + if (mIapHelper.safeGetOwnedList(OwnedProduct.this, + mProductType, + mIapHelper.getShowErrorDialog()) == true) { + return; + } + } + mErrorVo.setError(HelperDefine.IAP_ERROR_INITIALIZATION, mContext.getString(R.string.mids_sapps_pop_unknown_error_occurred)); + onEndProcess(); + } + + @Override + public void onReleaseProcess() { + Log.i(TAG, "OwnedProduct.onReleaseProcess"); + try { + if (mOnGetOwnedListListener != null) { + mOnGetOwnedListListener.onGetOwnedProducts(mErrorVo, mOwnedList); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ProductsDetails.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ProductsDetails.java new file mode 100644 index 000000000..e0f736910 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/service/ProductsDetails.java @@ -0,0 +1,63 @@ +package com.samsung.android.sdk.iap.lib.service; + +import android.content.Context; +import android.util.Log; + +import com.samsung.android.sdk.iap.lib.R; +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; +import com.samsung.android.sdk.iap.lib.helper.IapHelper; +import com.samsung.android.sdk.iap.lib.listener.OnGetProductsDetailsListener; +import com.samsung.android.sdk.iap.lib.vo.ProductVo; + +import java.util.ArrayList; + +/** + * Created by sangbum7.kim on 2018-02-28. + */ + +public class ProductsDetails extends BaseService { + private static final String TAG = ProductsDetails.class.getSimpleName(); + + private OnGetProductsDetailsListener mOnGetProductsDetailsListener = null; + private static String mProductIds = ""; + protected ArrayList mProductsDetails = null; + + public ProductsDetails(IapHelper _iapHelper, Context _context, OnGetProductsDetailsListener _onGetProductsDetailsListener) { + super(_iapHelper, _context); + mOnGetProductsDetailsListener = _onGetProductsDetailsListener; + } + + public static void setProductId(String _productIds) { + mProductIds = _productIds; + } + + public void setProductsDetails(ArrayList _ProductsDetails) { + this.mProductsDetails = _ProductsDetails; + } + + @Override + public void runServiceProcess() { + Log.i(TAG, "succeedBind"); + if (mIapHelper != null) { + if (mIapHelper.safeGetProductsDetails(ProductsDetails.this, + mProductIds, + mIapHelper.getShowErrorDialog()) == true) { + return; + } + } + mErrorVo.setError(HelperDefine.IAP_ERROR_INITIALIZATION, mContext.getString(R.string.mids_sapps_pop_unknown_error_occurred)); + onEndProcess(); + } + + @Override + public void onReleaseProcess() { + Log.i(TAG, "OwnedProduct.onEndProcess"); + try { + if (mOnGetProductsDetailsListener != null) { + mOnGetProductsDetailsListener.onGetProducts(mErrorVo, mProductsDetails); + } + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/BaseVo.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/BaseVo.java new file mode 100644 index 000000000..76c8f39c2 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/BaseVo.java @@ -0,0 +1,146 @@ +package com.samsung.android.sdk.iap.lib.vo; + +import android.text.format.DateFormat; + +import org.json.JSONException; +import org.json.JSONObject; + +public class BaseVo { + private String mItemId; + private String mItemName; + private Double mItemPrice; + private String mItemPriceString; + private String mCurrencyUnit; + private String mCurrencyCode; + private String mItemDesc; + private String mType; + private Boolean mIsConsumable; + + public BaseVo() { + } + + public BaseVo(String _jsonString) { + try { + JSONObject jObject = new JSONObject(_jsonString); + + setItemId(jObject.optString("mItemId")); + setItemName(jObject.optString("mItemName")); + setItemPrice(jObject.optDouble("mItemPrice")); + setItemPriceString(jObject.optString("mItemPriceString")); + setCurrencyUnit(jObject.optString("mCurrencyUnit")); + setCurrencyCode(jObject.optString("mCurrencyCode")); + setItemDesc(jObject.optString("mItemDesc")); + setType(jObject.optString("mType")); + Boolean isConsumable = false; + if (jObject.optString("mConsumableYN") != null && jObject.optString("mConsumableYN").equals("Y")) { + isConsumable = true; + } + setIsConsumable(isConsumable); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public String getItemId() { + return mItemId; + } + + public void setItemId(String _itemId) { + mItemId = _itemId; + } + + public String getItemName() { + return mItemName; + } + + public void setItemName(String _itemName) { + mItemName = _itemName; + } + + public Double getItemPrice() { + return mItemPrice; + } + + public void setItemPrice(Double _itemPrice) { + mItemPrice = _itemPrice; + } + + public String getItemPriceString() { + return mItemPriceString; + } + + public void setItemPriceString(String _itemPriceString) { + mItemPriceString = _itemPriceString; + } + + public String getCurrencyUnit() { + return mCurrencyUnit; + } + + public void setCurrencyUnit(String _currencyUnit) { + mCurrencyUnit = _currencyUnit; + } + + public String getCurrencyCode() { + return mCurrencyCode; + } + + public void setCurrencyCode(String _currencyCode) { + mCurrencyCode = _currencyCode; + } + + public String getItemDesc() { + return mItemDesc; + } + + public void setItemDesc(String _itemDesc) { + mItemDesc = _itemDesc; + } + + public String getType() { + return mType; + } + + public void setType(String _itemDesc) { + mType = _itemDesc; + } + + public Boolean getIsConsumable() { + return mIsConsumable; + } + + public void setIsConsumable(Boolean _consumableYN) { + mIsConsumable = _consumableYN; + } + + + public String dump() { + String dump = null; + + dump = "ItemId : " + getItemId() + "\n" + + "ItemName : " + getItemName() + "\n" + + "ItemPrice : " + getItemPrice() + "\n" + + "ItemPriceString : " + getItemPriceString() + "\n" + + "ItemDesc : " + getItemDesc() + "\n" + + "CurrencyUnit : " + getCurrencyUnit() + "\n" + + "CurrencyCode : " + getCurrencyCode() + "\n" + + "IsConsumable : " + getIsConsumable() + "\n" + + "Type : " + getType(); + + return dump; + } + + protected String getDateString(long _timeMills) { + String result = ""; + String dateFormat = "yyyy-MM-dd HH:mm:ss"; + + try { + result = DateFormat.format(dateFormat, _timeMills).toString(); + } catch (Exception e) { + e.printStackTrace(); + result = ""; + } + + return result; + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ConsumeVo.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ConsumeVo.java new file mode 100644 index 000000000..87fef9461 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ConsumeVo.java @@ -0,0 +1,75 @@ +package com.samsung.android.sdk.iap.lib.vo; + +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +public class ConsumeVo { + private static final String TAG = ConsumeVo.class.getSimpleName(); + + private String mPurchaseId; + private String mStatusString; + private int mStatusCode; + + private String mJsonString = ""; + + public ConsumeVo(String _jsonString) { + setJsonString(_jsonString); + try { + JSONObject jObject = new JSONObject(_jsonString); + + Log.i(TAG, jObject.toString(4)); + + setPurchaseId(jObject.optString("mPurchaseId")); + setStatusString(jObject.optString("mStatusString")); + setStatusCode(jObject.optInt("mStatusCode")); + } catch (JSONException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public String getPurchaseId() { + return mPurchaseId; + } + + public void setPurchaseId(String _paymentId) { + mPurchaseId = _paymentId; + } + + public String getStatusString() { + return mStatusString; + } + + public void setStatusString(String _statusString) { + mStatusString = _statusString; + } + + public int getStatusCode() { + return mStatusCode; + } + + public void setStatusCode(int _statusCode) { + mStatusCode = _statusCode; + } + + public String getJsonString() { + return mJsonString; + } + + public void setJsonString(String _jsonString) { + mJsonString = _jsonString; + } + + public String dump() { + String dump = null; + + dump = "PurchaseId : " + getPurchaseId() + "\n" + + "StatusString : " + getStatusString() + "\n" + + "StatusCode : " + getStatusCode(); + + return dump; + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ErrorVo.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ErrorVo.java new file mode 100644 index 000000000..8f691fe2d --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ErrorVo.java @@ -0,0 +1,59 @@ +package com.samsung.android.sdk.iap.lib.vo; + +import com.samsung.android.sdk.iap.lib.helper.HelperDefine; + +public class ErrorVo { + private int mErrorCode = HelperDefine.IAP_PAYMENT_IS_CANCELED; + private String mErrorString = ""; + private String mErrorDetailsString = ""; + private String mExtraString = ""; + private boolean mShowDialog = false; + + public void setError(int _errorCode, String _errorString) { + mErrorCode = _errorCode; + mErrorString = _errorString; + } + + public void setError(int _errorCode, String _errorString, String _errorDetails) { + mErrorCode = _errorCode; + mErrorString = _errorString; + mErrorDetailsString = _errorDetails; + } + + public int getErrorCode() { + return mErrorCode; + } + + public String getErrorString() { + return mErrorString; + } + + public String getErrorDetailsString() { + return mErrorDetailsString; + } + + public String getExtraString() { + return mExtraString; + } + + public void setExtraString(String _extraString) { + mExtraString = _extraString; + } + + public boolean isShowDialog() { + return mShowDialog; + } + + public void setShowDialog(boolean _showDialog) { + mShowDialog = _showDialog; + } + + public String dump() { + String dump = + "ErrorCode : " + getErrorCode() + "\n" + + "ErrorString : " + getErrorString() + "\n" + + "ErrorDetailsString : " + getErrorDetailsString() + "\n" + + "ExtraString : " + getExtraString(); + return dump; + } +} diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/OwnedProductVo.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/OwnedProductVo.java new file mode 100644 index 000000000..9bb1c9c4e --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/OwnedProductVo.java @@ -0,0 +1,115 @@ +package com.samsung.android.sdk.iap.lib.vo; + +import android.util.Base64; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; + +public class OwnedProductVo extends BaseVo { + private static final String TAG = OwnedProductVo.class.getSimpleName(); + + private String mPaymentId; + private String mPurchaseId; + private String mPurchaseDate; + private String mPassThroughParam; + + // Expiration date for a item which is "subscription" type + // ======================================================================== + private String mSubscriptionEndDate = ""; + // ======================================================================== + + private String mJsonString = ""; + + public OwnedProductVo() { + } + + public OwnedProductVo(String _jsonString) { + super(_jsonString); + setJsonString(_jsonString); + + try { + JSONObject jObject = new JSONObject(_jsonString); + setPaymentId(jObject.optString("mPaymentId")); + setPurchaseId(jObject.optString("mPurchaseId")); + setPurchaseDate(getDateString(jObject.optLong("mPurchaseDate"))); + jObject.remove("mPurchaseDate"); + jObject.put("mPurchaseDate", getPurchaseDate()); + + String decodedPassThroughParam = new String(Base64.decode(jObject.optString("mPassThroughParam"), 0), "UTF-8"); + setPassThroughParam(decodedPassThroughParam); + + if (jObject.optLong("mSubscriptionEndDate") != 0) { + setSubscriptionEndDate(getDateString(jObject.optLong("mSubscriptionEndDate"))); + } + jObject.remove("mSubscriptionEndDate"); + jObject.put("mSubscriptionEndDate", getSubscriptionEndDate()); + setJsonString(jObject.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + public String getPaymentId() { + return mPaymentId; + } + + public void setPaymentId(String _paymentId) { + mPaymentId = _paymentId; + } + + public String getPurchaseId() { + return mPurchaseId; + } + + public void setPurchaseId(String _purchaseId) { + mPurchaseId = _purchaseId; + } + + public String getPurchaseDate() { + return mPurchaseDate; + } + + public void setPurchaseDate(String _purchaseDate) { + mPurchaseDate = _purchaseDate; + } + + public String getSubscriptionEndDate() { + return mSubscriptionEndDate; + } + + public void setSubscriptionEndDate(String _subscriptionEndDate) { + mSubscriptionEndDate = _subscriptionEndDate; + } + + public String getPassThroughParam() { + return mPassThroughParam; + } + + public void setPassThroughParam(String _passThroughParam) { + mPassThroughParam = _passThroughParam; + } + + public String getJsonString() { + return mJsonString; + } + + public void setJsonString(String _jsonString) { + mJsonString = _jsonString; + } + + public String dump() { + String dump = super.dump() + "\n"; + + dump += "PaymentID : " + getPaymentId() + "\n" + + "PurchaseID : " + getPurchaseId() + "\n" + + "PurchaseDate : " + getPurchaseDate() + "\n" + + "PassThroughParam : " + getPassThroughParam() + "\n" + + "SubscriptionEndDate : " + getSubscriptionEndDate(); + + return dump; + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ProductVo.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ProductVo.java new file mode 100644 index 000000000..635056069 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/ProductVo.java @@ -0,0 +1,223 @@ +package com.samsung.android.sdk.iap.lib.vo; + +import org.json.JSONException; +import org.json.JSONObject; + +public class ProductVo extends BaseVo { + private static final String TAG = ProductVo.class.getSimpleName(); + + //Subscription data + private String mSubscriptionDurationUnit; + private String mSubscriptionDurationMultiplier; + + // Tiered Subscription data + private String mTieredPrice = ""; + private String mTieredPriceString = ""; + private String mTieredSubscriptionYN = ""; + private String mTieredSubscriptionDurationUnit = ""; + private String mTieredSubscriptionDurationMultiplier = ""; + private String mTieredSubscriptionCount = ""; + private String mShowStartDate = ""; + private String mShowEndDate = ""; + + private String mItemImageUrl; + private String mItemDownloadUrl; + private String mReserved1; + private String mReserved2; + private String mFreeTrialPeriod; + + private String mJsonString; + + public ProductVo() { + } + + public ProductVo(String _jsonString) { + super(_jsonString); + setJsonString(_jsonString); + + try { + JSONObject jObject = new JSONObject(_jsonString); + + setSubscriptionDurationUnit(jObject.optString("mSubscriptionDurationUnit")); + setSubscriptionDurationMultiplier(jObject.optString("mSubscriptionDurationMultiplier")); + + setTieredSubscriptionYN(jObject.optString("mTieredSubscriptionYN")); + setTieredSubscriptionDurationUnit(jObject.optString("mTieredSubscriptionDurationUnit")); + setTieredSubscriptionDurationMultiplier(jObject.optString("mTieredSubscriptionDurationMultiplier")); + setTieredSubscriptionCount(jObject.optString("mTieredSubscriptionCount")); + setTieredPrice(jObject.optString("mTieredPrice")); + setTieredPriceString(jObject.optString("mTieredPriceString")); + setShowStartDate(getDateString(jObject.optLong("mShowStartDate"))); + setShowEndDate(getDateString(jObject.optLong("mShowEndDate"))); + + setItemImageUrl(jObject.optString("mItemImageUrl")); + setItemDownloadUrl(jObject.optString("mItemDownloadUrl")); + setReserved1(jObject.optString("mReserved1")); + setReserved2(jObject.optString("mReserved2")); + setFreeTrialPeriod(jObject.optString("mFreeTrialPeriod")); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public String getSubscriptionDurationUnit() { + return mSubscriptionDurationUnit; + } + + public void setSubscriptionDurationUnit(String _subscriptionDurationUnit) { + mSubscriptionDurationUnit = _subscriptionDurationUnit; + } + + public String getSubscriptionDurationMultiplier() { + return mSubscriptionDurationMultiplier; + } + + public void setSubscriptionDurationMultiplier( + String _subscriptionDurationMultiplier) { + mSubscriptionDurationMultiplier = _subscriptionDurationMultiplier; + } + + public String getTieredSubscriptionYN() { + return mTieredSubscriptionYN; + } + + public void setTieredSubscriptionYN(String _tieredSubscriptionYN) { + this.mTieredSubscriptionYN = _tieredSubscriptionYN; + } + + public String getTieredPrice() { + return mTieredPrice; + } + + public void setTieredPrice(String _tieredPrice) { + this.mTieredPrice = _tieredPrice; + } + + public String getTieredPriceString() { + return mTieredPriceString; + } + + public void setTieredPriceString(String _tieredPriceString) { + this.mTieredPriceString = _tieredPriceString; + } + + public String getTieredSubscriptionDurationUnit() { + return mTieredSubscriptionDurationUnit; + } + + public void setTieredSubscriptionDurationUnit(String _tieredSubscriptionDurationUnit) { + this.mTieredSubscriptionDurationUnit = _tieredSubscriptionDurationUnit; + } + + public String getTieredSubscriptionDurationMultiplier() { + return mTieredSubscriptionDurationMultiplier; + } + + public void setTieredSubscriptionDurationMultiplier(String _tieredSubscriptionDurationMultiplier) { + this.mTieredSubscriptionDurationMultiplier = _tieredSubscriptionDurationMultiplier; + } + + public String getTieredSubscriptionCount() { + return mTieredSubscriptionCount; + } + + public void setTieredSubscriptionCount(String _tieredSubscriptionCount) { + this.mTieredSubscriptionCount = _tieredSubscriptionCount; + } + + public String getShowStartDate() { + return mShowStartDate; + } + + public void setShowStartDate(String showStartDate) { + this.mShowStartDate = showStartDate; + } + + public String getShowEndDate() { + return mShowEndDate; + } + + public void setShowEndDate(String showEndDate) { + this.mShowEndDate = showEndDate; + } + + public String getItemImageUrl() { + return mItemImageUrl; + } + + public void setItemImageUrl(String _itemImageUrl) { + mItemImageUrl = _itemImageUrl; + } + + public String getItemDownloadUrl() { + return mItemDownloadUrl; + } + + public void setItemDownloadUrl(String _itemDownloadUrl) { + mItemDownloadUrl = _itemDownloadUrl; + } + + public String getReserved1() { + return mReserved1; + } + + public void setReserved1(String _reserved1) { + mReserved1 = _reserved1; + } + + public String getReserved2() { + return mReserved2; + } + + public void setReserved2(String _reserved2) { + mReserved2 = _reserved2; + } + + public String getFreeTrialPeriod() { + return mFreeTrialPeriod; + } + + public void setFreeTrialPeriod(String _freeTrialPeriod) { + mFreeTrialPeriod = _freeTrialPeriod; + } + + public String getJsonString() { + return mJsonString; + } + + public void setJsonString(String _jsonString) { + mJsonString = _jsonString; + } + + public String tieredDump() { + String dump = ""; + if (getTieredSubscriptionYN().equals("Y") == true) { + dump = "TieredSubscriptionYN : " + getTieredSubscriptionYN() + "\n" + + "TieredPrice : " + getTieredPrice() + "\n" + + "TieredPriceString : " + getTieredPriceString() + "\n" + + "TieredSubscriptionCount : " + getTieredSubscriptionCount() + "\n" + + "TieredSubscriptionDurationUnit : " + getTieredSubscriptionDurationUnit() + "\n" + + "TieredSubscriptionDurationMultiplier : " + getTieredSubscriptionDurationMultiplier() + "\n" + + "ShowStartDate : " + getShowStartDate() + "\n" + + "ShowEndDate : " + getShowEndDate(); + + } + return dump; + } + + public String dump() { + String dump = super.dump() + "\n"; + + dump += "SubscriptionDurationUnit : " + + getSubscriptionDurationUnit() + "\n" + + "SubscriptionDurationMultiplier : " + + getSubscriptionDurationMultiplier() + "\n" + + "ItemImageUrl : " + getItemImageUrl() + "\n" + + "ItemDownloadUrl : " + getItemDownloadUrl() + "\n" + + "Reserved1 : " + getReserved1() + "\n" + + "Reserved2 : " + getReserved2() + "\n" + + "FreeTrialPeriod : " + getFreeTrialPeriod() + "\n" + + tieredDump(); + return dump; + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/PurchaseVo.java b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/PurchaseVo.java new file mode 100644 index 000000000..9181cbbf5 --- /dev/null +++ b/IAP6Helper/src/main/java/com/samsung/android/sdk/iap/lib/vo/PurchaseVo.java @@ -0,0 +1,172 @@ +package com.samsung.android.sdk.iap.lib.vo; + +import android.util.Base64; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; + +public class PurchaseVo extends BaseVo { + private static final String TAG = PurchaseVo.class.getSimpleName(); + + private String mPaymentId; + private String mPurchaseId; + private String mPurchaseDate; + private String mVerifyUrl; + private String mPassThroughParam; + + private String mItemImageUrl; + private String mItemDownloadUrl; + private String mReserved1; + private String mReserved2; + private String mOrderId; + private String mUdpSignature; + + private String mJsonString; + + public PurchaseVo(String _jsonString) { + super(_jsonString); + setJsonString(_jsonString); + + try { + JSONObject jObject = new JSONObject(_jsonString); + + setPaymentId(jObject.optString("mPaymentId")); + setPurchaseId(jObject.optString("mPurchaseId")); + setPurchaseDate(getDateString(jObject.optLong("mPurchaseDate"))); + jObject.remove("mPurchaseDate"); + jObject.put("mPurchaseDate", getPurchaseDate()); + String decodedPassThroughParam = new String(Base64.decode(jObject.optString("mPassThroughParam"), 0), "UTF-8"); + setPassThroughParam(decodedPassThroughParam); + + setItemImageUrl(jObject.optString("mItemImageUrl")); + setItemDownloadUrl(jObject.optString("mItemDownloadUrl")); + setReserved1(jObject.optString("mReserved1")); + setReserved2(jObject.optString("mReserved2")); + setOrderId(jObject.optString("mOrderId")); + + setVerifyUrl(jObject.optString("mVerifyUrl")); + setUdpSignature(jObject.optString("mUdpSignature")); + + setJsonString(jObject.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + public String getPaymentId() { + return mPaymentId; + } + + public void setPaymentId(String _paymentId) { + mPaymentId = _paymentId; + } + + public String getPurchaseId() { + return mPurchaseId; + } + + public void setPurchaseId(String _purchaseId) { + mPurchaseId = _purchaseId; + } + + public String getPurchaseDate() { + return mPurchaseDate; + } + + public void setPurchaseDate(String _purchaseDate) { + mPurchaseDate = _purchaseDate; + } + + public String getVerifyUrl() { + return mVerifyUrl; + } + + public void setVerifyUrl(String _verifyUrl) { + mVerifyUrl = _verifyUrl; + } + + public String getPassThroughParam() { + return mPassThroughParam; + } + + public void setPassThroughParam(String _passThroughParam) { + mPassThroughParam = _passThroughParam; + } + + public String getItemImageUrl() { + return mItemImageUrl; + } + + public void setItemImageUrl(String _itemImageUrl) { + mItemImageUrl = _itemImageUrl; + } + + public String getItemDownloadUrl() { + return mItemDownloadUrl; + } + + public void setItemDownloadUrl(String _itemDownloadUrl) { + mItemDownloadUrl = _itemDownloadUrl; + } + + public String getReserved1() { + return mReserved1; + } + + public void setReserved1(String _reserved1) { + mReserved1 = _reserved1; + } + + public String getReserved2() { + return mReserved2; + } + + public void setReserved2(String _reserved2) { + mReserved2 = _reserved2; + } + + public String getOrderId() { + return mOrderId; + } + + public void setOrderId(String orderId) { + this.mOrderId = orderId; + } + + public String getUdpSignature() { + return mUdpSignature; + } + + public void setUdpSignature(String udpSignature) { + this.mUdpSignature = udpSignature; + } + + public String getJsonString() { + return mJsonString; + } + + public void setJsonString(String _jsonString) { + mJsonString = _jsonString; + } + + public String dump() { + String dump = super.dump() + "\n"; + + dump += "PaymentID : " + getPaymentId() + "\n" + + "PurchaseId : " + getPurchaseId() + "\n" + + "PurchaseDate : " + getPurchaseDate() + "\n" + + "PassThroughParam : " + getPassThroughParam() + "\n" + + "VerifyUrl : " + getVerifyUrl() + "\n" + + "ItemImageUrl : " + getItemImageUrl() + "\n" + + "ItemDownloadUrl : " + getItemDownloadUrl() + "\n" + + "Reserved1 : " + getReserved1() + "\n" + + "Reserved2 : " + getReserved2() + "\n" + + "UdpSignature : " + getUdpSignature(); + + return dump; + } +} \ No newline at end of file diff --git a/IAP6Helper/src/main/res/color/dialog_button_text_color.xml b/IAP6Helper/src/main/res/color/dialog_button_text_color.xml new file mode 100644 index 000000000..a2bed714a --- /dev/null +++ b/IAP6Helper/src/main/res/color/dialog_button_text_color.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/IAP6Helper/src/main/res/drawable-hdpi/tw_widget_progressbar_effect_holo_light.png b/IAP6Helper/src/main/res/drawable-hdpi/tw_widget_progressbar_effect_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..f8e90af625e08d13a7c418582e7f1239de90bbde GIT binary patch literal 3462 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 literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable-mdpi/tw_widget_progressbar_effect_holo_light.png b/IAP6Helper/src/main/res/drawable-mdpi/tw_widget_progressbar_effect_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..f8e90af625e08d13a7c418582e7f1239de90bbde GIT binary patch literal 3462 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 literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable-xhdpi/tw_widget_progressbar_effect_holo_light.png b/IAP6Helper/src/main/res/drawable-xhdpi/tw_widget_progressbar_effect_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..2960eb02aa5be63d001b229714ced515a348aae4 GIT binary patch literal 4351 zcmaJ_cT`i$_C`;dJnxyAOQk|ge3I(C`!kxfOJF=5JCr~ zh(ti8Nl`(n*yv3`nkfFleb@Vbf4uw7TIbBnS>N~VJ+t@hIqSrk7-{nzIdO!Ijg3!N z2ZLp`nEjiJll6oP-l}0WqI6Abx*6G(?vJAq*fj8DX97r%3eLroKnFP!+=$+);ML|)bB&)ywS_TaI6GHb? z1^?SAYeN$dnoK2t6rr*Z7g;4)kdho!4yK^2tSk+Zmz9&1k(HN`lZVJDBVqDLSy|9u z7no&@ig!g~F z$uxH|1%x(J1X&Ti@nnD6pJ+ovq^>uOj`MaQ=wejCEIyP-#3PloWYJ2B$|w{92A7l5 zl!wF67=)rSTpo?mL@2^gzquH)i!X`bP5;fs|A&kINA7+ikSHw67y^~(N5E@Q$t2L9 z6GjsM*%!n=>ixyV|FbU||HzeLIU}+D?v)}zYX<386)1KhX%5^F$sbjjjMmau!4+(|_!=cp?Z$02H84s=FFbh-q-p5i|9d9C_V zm5ROVwrf~zP4L#c)xFJ}Da7n3@k<6N`Pb-KkwjDxx9H0oDH{iYadRTUWZbU>@pqrS=E-k`#PA|{i` zbN%S4rb8ct&%5N^tk%lhwc+Z6=o=XDmX(($Ra8`LmOpqf-!blcMPh)xjw6>>LEumn zaNqzZ^X2HM&4*8)%;sliEWZy~U3Fk8HlOcCJhPCmvIL&(^@M73o;%zqYwqk(`p!KiL`{K4cAXYvU3J%fn!* zDW_GlLYBuAi#Inn7Xx;MP5Ny*+{qEpJI)<*q6jrgeZ-wRchU(x=|9(hZcSCzrDce3 z8IuzaEs2#jG&EQsb64JO(}eiB8){FA8V@Z?zTo3JjJ*T9EG%tZH8asjv$f+ErK`J~ z#jFk6kww4iwX zg>MX5h3Y-|22L*xteP;b$jLkD#26X= zHw@mwJVSd-F?U-lN5^;Sl%$7o$1Dh1T3Sb5CzuEeKeH7__$_5rS5&N!#CDb6Yl1js zZ+^KsGXe?%ZaNq{ovz}8n_Ruxx|&UX!aY;jKXdFLLsw7FR(~p2%GAPZvdQ;>!Fjus z^@FhRGldtvZ0t}9qTqg#{Qcf2xn$i`G0I_K_RDj&Q=wav&OC~u4zP$0zxHcHMVTe3ed{h_@`f0k0=ipYpEhx}54aA9O+9{= zy82!_r^inI{&)R!>A<{+UQ1M=j`s|)eoWE^3VISD+_a`Gc8eW8Hs}m!T#8>)5X#2rd+UEPh#U%6$h7I@t9O6Ihx>Bn=IeLi*ws;Q}&zZ9;1Gw#S~@#fdY zw{JfVtUOLnP*LdjY;0^ym4_$8<>qC^Zt(T3t*r&c+q__M0Ra9F9y|!-c+o4`FXoa% zOB>Z$-|Fb-2w1a>e6trvZvE+J)ViJWhG1@EW3y4Jw zY;E;Ud{lA1t#LrJ%RqkC^XA*D;knoui1ZF{Dex_TMg!}=YxZCLWbaXFRyLFZ4v)wA zzN!)it5ZMgfNtjKS>^%E8+k;aIWP1=gC8dEX$Wnnx${B^SMc6ts>h5JGB-8-(Ah#xXZuNp&t_@$<% zzOgNtfB^3@N=rRH4nu^HxkmjMzf#523;_!GgRO zbY6KC$jZ9LSP>LWPEMYDe9#(Pcvv$xeV0-E5^w%l`BH%8aqP!lE~RY9${&UP?$%1gN*no9cB(f zU_r%q;aKV3iNm-MPx=9xingP zTDn=-Gq$_G-?*#$7LJ>EgpaRWS6BDz=ZSmwS%=Q(0x~l6D4G?HN6cl_lf0ah44c{& z8^#!faeV+daqlqT^aL|biuAoB?AxIBrLJSe%%IqB9dUx(+ma;Tc##~!?&fkZFuxLi zIikJdx`|Y&M%tXjxB7Fuu@IBp>DyPoTbBZtDRW29sEKu_U+Or;wlFv6Zo2`qVe~K< z4}$9I>svDZ_(PztF{#$F%uvm5X+-5=ntSE2cvnwP0>#(&z9v=qtDC8*samIg7&^E; zePzmHoZ}0;ZAjm~ZpWwHja6OkMo|?lz`NrOKA(gODkt?+!gmJmX)AwNw-^@AEcZsU zJ>}!$Yo6)LU3})yuX!J<+8DgGa=%b{^SFol_WLMn>ot#p%CE*=AFi>A$0Ypx<8XbN z!e#$Dp3T&l`yt=`xfEROOic&Tw^|xiC!{W1_!_M>kmE*OPk%b}T5ig%V?6WTSogs; zljFoB z=&n6W5DD*TtAK}#(+unO31(j)fOBY}DtN&6dsI6UB zeD$pQA)1Tv0aDc1xHGx5w8W2d&pt4{GanZh*RIrHm`Y$8Vr^FKxU8r;H8nMl1;k27 z5>K&!gmP8aI-c|+G4CD)uDf#h8)Y$59K!i)XVvz$U1qz0W1n86Tz>xi`AyeCI}qCX zNl0TwY3ahLnTt?MuKM!%qhIcl4D8<<)5XJZS&hawZ{L1W?i|4-U$rJd?>MS99-OR`?}RS7hqo;3P*Lc56^^C z0k#1)(Uf#^N5?REY3Zfawt=D$L|LLk2Jz%**?}0VM@Ge-9JT_(yVj{)?w*cOcoRNg zXD{&#t4c7;bBE=?+ZQeT_I~ULWwayjV*`QV`30*6mg}u>#JyP9^^RlE!pQe~hg==N zyrCX?-56uZ$h?+|nmdL7yIC(>0ulnQvjf>&pi6HSU=|LI3WF)urOy} zaB$@zft1c^>MLlFL3CEYiWBsd64&OoAQ;&gPvj}rF@0oe9vs|UQC(flHFjfmcGiC^ zaul$bHBhoMkcHt|lQ@xdjWMG_F`5gG?@^e5$pI2?>kp?HfNxs0&2xI zTWdq9Dg^9n_@;efe(wPMP1)ze(!A$!bW zLawL=p!&vgpM9_H@v+&VF3a}C5ko7kP-Ewzs*>08*ry?&=tOM9Zhq^K++FjwfuA2w zKa}zk);wvKw^dKN`TAEu_rMor)gta{wLKXoo3DsL?)iXT!Tnznx|&9q3Y1gi{{dI~ B&1L`q literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable-xhdpi/tw_widget_progressbar_holo_light.png b/IAP6Helper/src/main/res/drawable-xhdpi/tw_widget_progressbar_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..67f5018f20b2db689b172a8c76df6933e7727bfc GIT binary patch literal 4466 zcmaJ_c{r5q+aBvshDl`CG^ioWVx7r0%-D%B)+Eb}Ewh*zS(05LWGy0NEo6_BB`qqE zLbi~I3W-95(x>}cMsU=IcvfF;p9$q+M&hYy)R_8^4@J|pV@09+71q7%!> z$`a#6qo{iP#;Ar+=(}tHKu14>?%{Qs%z}85ef+4p(B;++D8!GX3w6}6LRis_$i9B2 zVGOcem^INW?6en}1l8Ar=!9T)1t?^e2PA|NKxJY=bfJIgVs_`hx8YF8Ul7)5UFd&I zIa%32jA#rpL_-y!;)T#eKs1r6NHujWEiGjT3V}qx5hyqkrGnJLsG%?j1my1rx*Lr_ z^2QKw#(&4!UFkx7Su8pR4i63vRt;8Dr7?WqNHiM#TLXns*+r-@L#Zr}5EUv@?vDbF z%=BXT(OG^pD&)7KhbJwFr3>A4`kxdi^nYZj%)iUDTQGQt2OW-7Mf^_b575f$|A$g2 z|Dc&H0{Opw|4(5iF_cb*6Ua@KJ#LTu(NEl6=1`3PBqYcq&+DIfGrEP@8 z;*5+D+6ZG~gpnrh4;M%C3ZjsytUp}Rf4SIy<^FC23Vk;+j?C~oLnawBXcWj_31j^J z-HX=0>ix|n{ks?Kf91k=&A@*j>;F3DKU=%K^LzSF)9x<*X?rqtx7QiFO)XqGVYhqH z=FD(dV#wH{D=p#VV^Q|1+r*heVAGpc{IJt<(FPV{*&x5n!>2^B70MbZLrUq~7Zun8 z*AJ)Q3@Hu%_MPv5_3|+Oga?I?eVy(GmQqb-kIyTEKqnU{3Mv|ld;&G!M2%T;>iWn1p#)O^P&0BTytF9^QlUc$FZzppgJFML_;$UAAU z2u#ZT24|=%k_At)s~z5*y?fN6AARuJ-hNrSV?O?F0xBAn#2Co-TDh(0p(w7zBe#`S z?z@i0*>zX3bIP3HF88X5`VkCqV6exaQnJfby#+@Tn}g$pB(_ug-Xs#Xgt8t^`+|dOd-8WhV)%P6Udg-@((+#AxVBkuX#zagk z(!xCZGn>atZ>+U%2RJ6=YnUS^Xgcn$>zP! zS#-wbO&a|;?am<6Vk%*?F!BZ$FTnQTw>`Y)6froEfqt8%W$gM$RR+QZr{w&q*VFvN z1W$NMkt_Y0i$G0K5a=Z_ZNQ7oLy@wrHG2DcJ_hM!P=NXQ8WHh<=h5w1oJsZ`hs~kK z(Oh^_T5%|!j0xSp>d|Kn#7&#wl8Ly}+n>aQnTUjyL*4DAktKox{=hE+xDOR}GkMt2 z9tT?8o)gd!!Lav1S>yfRCA&Y*y}d9~uPX1IyjE%0?P}3ISj&Tg-Kv}embhWt@5+c1 zONy?8x-uiTmj%IV0x;?mgStLYxHMTqvbktkBmZjS1gg4swv^{lRD&c-rdIDu*Y_~q z6q#?vZvJzN8e-(#k0Ux zpyyu&#NQXT-*K-S{=rV{`ms~{%Q>#1V^8-s7hoT3yRTXD+otISqJJ>uSRJ9KCCrAC zDVs9nyVMg^1oX4mv|m%X>^fbPQ`4mrv0`|zyw6>E-9UUy2R8oo+(Ah@@+p^(fH~_t zl4gL2;-KQ-Mp6BnSgeR+j2p!PR#7|xYZ;4e2$&oewV&@enX~;5W~z64?)>Ct^&~-?3bas$B>c@_p*M>C?K9!b|&+2Iz~mR_UsV zFK#Avb&+#LgPlCg4P%$(5|Wh?v)r>vsfII__Ks->a&@Dz<-zHpYwee=L??K3u(}m4 zZ;Exe?0gI4u;I;WR9O_QM_R_mHT2ZVxA6+}h|XxY)Joe4Q}fi5Ysr

oxsuL0=pw z;r9H>lM`ESPEW!_Z!W`a#CR4S4$u3GaE(0xCpzqhEA10^3(ct0c>XMy9&P}zEua+# zG`X52I#zQ*{jjg`J&NH zyY6;wxewqn;Z$*^?CtxYb%&q66Ne%SEz&uH%d@mk6eOQVBVxMfUO>@flE6@HQ7phQb{cARE8ERmIqec=!%47 zJyo$w;*(Ex<;>7NA!(L)SN>+7v&V$xSHp{iY;LFDBnezD1Vxa?`kVe zW}6BP8{MpBS8)=Yz}?w~l7iHCRs4$T={$9u>EagDwnJ^NMYgy;N`Z#J(nT=mFniDX z%1YUc7YYp#Sn8R1yR?R|*tTfh9ZQ&+zXlPeOas#fdq1(q+Vlhq?)!(B4obt^|>n*D%a* znG5bG*wm;HkBESDdQ|d;w<~9SlZm=mqv|Q!>Iy}!=a zRQhzbq8O1Up0L58czW~uBceI4C-ox=JX}`R9e#MM@3qx<#^R5TG2`f_g4hz}O5zRf}1DwK? z`EA5@k@N+kW}qyePfgy;WyO27*#TRfPm;O8vdJsj9LDdfUWW*&$JJgh9z7WqSu#lB z-FNsq)-yKivxX+)!1!7|$fbUC=hjrAgE#Q`Gpb|W7OBeRS69B&gQF&?l9f=E2LoF89H#O=9=R=xc9;Q0+xEh=wD+CA4Svv5j~-a!`uRu|}a=ge3reMlv6P-_?o(wX1!4806VNOAdzVre_DlKX7C zZ=RP=L&uWB0(!Lf@gd6)=#0kOFL{oWCqzD_J>0}|PbW6_Ruf-?@n>R(Q@?AvLPb78 ziBfH^(D`f|)uQW1YPaR|w3D4kty*`tfxXZCIdf;f9khUtaG4v|A3;E9qCry zOW--fTURb`jvkMsi_E^|k8$xcOrD7bmA^G7$?dDfMWuqx{ zGVroR%a@-nFT}YyFw1M)g4Dzqdt0!DkM1i><1Z&r06y3Fl|{=N#oCd(PSUhu(5k zb%v}I_F0}HO*Sl7$B+4I(5#xCY4zm4GCMmaEc?w`{w!6|Wu#cP%Z;sF7jLo?G`Jxt zhXS3gb9$-mw!X0(QMmUA6MoP^%$E8{Xd>QBFFF<9R22PPE$RiwO#Dn7_ReHJTz6@5 zy2cUg(9xO5B|rJfV}npSFZT(lRx^hZtVSz561ernI9n{8%XcE`(LQO*S>=(1g7d8x zWoOz;0y^`|tQ4vmy3c2cH2dM69*GA>_XiV0?p`%QUE)8Zu&=|}q0%$An#0(s;$!tTRq`OvxG+;` z+A^=6v<)S@C^-Y21l}pbTYu5mcYn!v3Z|hA!nS@KkKzDGK4}c(DdKtd`!9$Y-Wpe9 H=pOSw&pF0^ literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable-xxhdpi/tw_widget_progressbar_effect_holo_light.png b/IAP6Helper/src/main/res/drawable-xxhdpi/tw_widget_progressbar_effect_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..7e4cdecca5485dd4d8dfb58cc1e6826d22038bf4 GIT binary patch literal 6121 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 F{{vSH>v;eG literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable/circle_60x60_dark.png b/IAP6Helper/src/main/res/drawable/circle_60x60_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..7b6235e74853928f8d882f2195a99e472c3fe8ee GIT binary patch literal 2666 zcmV-w3YGPVP)Px{$2vtcCBTA8AS_qJU2CAhR z_(KDUil9+cjEM>%6%!?<2(~aqf z!;>;)MKyLD+Bgd6kK44r9~N!>tEx>)Pe4v5JC*ssvf_~7kgE)C2Rl-+^=sm#)wHi) zs#LDfGM*ftf<@cB^Xk^HWxVVDKf38Dm(lTy6)fY*wOth1tH)R4cEe~~7>X{yxFVc6 z=!8J8bxxrY<90)`eA&ol##ouJKPGFKyE54VnjYQs8Az|}HnLu(0!PDiUV(fbx_lawVj<0h?-^PDK#(}A(!H&E7|r$NV7#5*P4)SLp&^2_eo=2Tpf+!N@52W};oUCe4QwfjHNvh#H- zKVON`pbN_{3J4cBeyu~OO|P*lXqH(&mUmvkIq5rsrYq)37r0IhS0a~!rhvm5v!yyD zOnIZXeb%f)o=L*E$VvgmashPuBWD}+x_5xs#l#)}Se;OZNV(IzSsMbpjO^*7l$!(|sEc z7>^c^&q|*Jq&F9P&*m$S@7($e@4cL!g%FDtpjog8%4s(g%P@or8izqXS!W`FyzuB+ zC=jARLE}6-ms(Z;Cb@jbn8h6d_TgPXC=mn-x^84Y)EqkmHOGgb<-l)&Zm>vjcoJ!S zM|A2*Rf3ibG^hUQBacAO*Kbkr>@oeZ55dIxOCZ}s=UWqckPpITfzH<^Vdy6}Lp~AC z=<*DD@aMM@u*D4<;Bf`R$7;Y6mpcI?*$Cx=4-J@pCG-4V5#|MC{6tV>1!ee}jl4QvYrKhOoE zfI|Qcg*$ZngU<=dx(Gzjx*&7G!GXqQW;Fy3^h|HNfjJi9xt zo;JP0*dAyLIrB4toJ(EXdcM~uQ+3{$Xz#USj8aIL+iG}OuIRLYbN^0OQqkrHWxbRzT3#V#DuxGjc;ks zdHQNsz*rdC@Ho0^6W}V20|F&{a7+c;2fcSCylqI;iDQ zMnv;`1eOcz9$pFJ+`TasmrWOBff0@V3!~_C(QNJ$Nih%-7YvUX?}Y2$9FVGhHIdJfL? zIao$6D^n)gbV$F6+p&$!Wr*7}`C5SH9z$%0!%8a?jb8ukwz%P&e)ra}a93TsN}Ea} z-(E+i3r3YZXcz|os;;}?0cO~fgFr9HxpuO-!-S=ey%NeP3kE{fB})>GCz{xRA8S0_ zAD7ww`jvJi8n-L$$Htm>lM~!g@XUZK(UW8wlMCdlB=dEGjBEEa$hZ=nUA&O%BJNv6 zp*#j$iB6nIb5@f_i(kCs3ZhI&210woQWBZw3Wkr+dh`)WLGr`^^gMMn#B&)()UG4i zu~t+7!$@*%v+)p@Nu6W33%St}5$(o~OIa>Kyxo{kGyOi36O$3qA}1v!v#BnC1n*K< ze|WEJy@+U6dgO)U7k`5~Jvu=VWeGnQyPH+JNT2Vlzh?|%H~MUwDzDNYkAOE){IviuoC zG#=>3N9V~4$oB^eN6rO8$Q-=*wV#$ezAMyI5S&&-<7Usv&QHQj=Nd?NTnw4U4%<_l zgb}ib-1^4Do>vhPORl1-B)b30`^>#y*RDAflCM299oz*=_k7p!djt+OD-u^F(earH zccRG@5TBWZy3qr$ux|$;cBgN1ZMkemud>Qz&SSl3ufro@<*G+Sm&=^TdJ)kc2`g9q Y|N5t~hNVI1Q2+n{07*qoM6N<$f>fa!Y5)KL literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable/circle_60x60_light.png b/IAP6Helper/src/main/res/drawable/circle_60x60_light.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd0dd532e3a33d9de89e24bb5b9c224ea2e2a57 GIT binary patch literal 2621 zcmV-D3c~e?P)Px;_en%SRCodHT?uR!MHGI!J%9o&mjP(4WLzVcKw6e`1*S5c~U<&yHnh~)-d z1heVOiV8&pljNILD^Jz4GF4fW?O54PM|`p2tFjwYc4dyLJ+ERL(1$zq?7^^jXt7;; z*E|byI@p~YKi9P(OQ8Wd3JyXj?O1)9_-ai%dnnBhBvys@%E^PbhF%khP%6a2IW0&w zW>WHGgzE)kdzF@Cgz4Lu1!Gy#wBX1=2L$slPdiOoI2GU)hbBBQzRlG5rudm;^ z0@haVm5cnmwT^=6xFQMyl#jXxdgXMm>(?>QA{b2~v~nhO9S9!|pXAuktH2@{h5ET= zrw$Ac4{v|}m7}$*&x8eG0M~_aE`k*Yir4OSPFn*>E-=|F+0uhWt z0VL>(4OP7=jS#&Saz(CZEdJMFy__A?i!^=+idNFhB;h= zmWa`dp=6{SseiZyjg~qFG_1{mOPy}FNQAmZ0YpK9`We=#1y@WXJeIj>9#^zp`eDA=?R>J!c@goZl^_`)~nybaGogY2K9A?evB z4<7AzDcoLgo|YM6iW&5x${jGLe4`4bZAKOxymDqF200Vx3rgRHJ;x8rfXO5sYOkJ6 zEUoAU9#7Eyx4Z^bb;o4D`K{YS#pwG~wxde8(p9|UV-@fNy$iVjj6^wt-gCSLHXZ&$ zCUa!R0w@_YR!;Nq$IG1xLaW#>w@0&jp3m@Viv)xXK0(`GI2 zoj-S}EaR#vkHNz9{blQAoP~Mac*HAXvVfMzhAW1xmrR#q9{*TC^9a(6$p9M7%yb9_ z(3@-ikTJIs6rWOFZ@>WhK;2OpXHI4ouXtr#2GFYtr;tnmz9^c?HE74rI1i|)FNJw+ z&%iVfKv^)vpjlXAt+TkyxhA(vKli-??W`Q@_64_~D~~FhL@$oweEWhb1X<2j!_+}) zQcZBlbZ6q;h#@P(sv4Nj9q4+Z4JU}}B!+|cSXBe_xdWZ^iUKK9lpt50BRe-7!idwvIx% zQkX%%mzYm>X}tg=mdMnjWV^Pdj6lZqOu&8{7h5bdhZbjg#8MG<98^?+g4s2_3C<<^ zjjSOw&}GEIWb`r-PLj`CeUlL+1y|fR0jnn3e?Vv*yEwELF>?WGo)xS>wwB)Y%pi6b#7e1kay4Hq!lV z3s}aC$j0dR$PU`V%I#2otcL9H__6W?a;Rbsfaa9Xr}ep__D$M7@cG{jkxuUAA_9;ruoc7;|DK);{t;n+?rSs)mJ{8mNPX< zKug8UM5EWg{+AEXH~kRtO^*W`15Arbh1=dX9Ie2K1|9&213LqrM57nvug8=_3smfq zVH2aDHlE77=IX+AbKmrSAK;GY3kqF>tgok1e5 zrnS@wGDF9w!G$Z)mH&|g-nxK`LUBlr0av2CwrXpT+Q;W_ei|B|;TMtZu%tWhvX2n) zXFE~{(2xA)>@UQZE!#zHU5e73ig59x)8LUh^lK7e?-4Djj3Q&A8Hm+aL3e5V*<>2fsrM5G@8g(g${0iZ#5S<_q@(9F%QP+~nt@=ff~OQp zwi}N`-#C!nJ)PxYFhV(ft4&!Wz^A_%brKIOd@#X#Y^JQlL{lbg;%YMM>$_O_y-9uX zlOvko$r1V-?{rMG14sJfVzdhWP~uNys_o~T5N#V1O_^wp@c`k%oyyc&UxX*e)=y?1 zD)enJ9TQDRz#*b=iKw2?)RTl~3HOnsd8rbWYI{AVv`XW-v0K&(uyQZaUY%V`Zvs!3 z;xG{uK|#r(__&SnK>t(34qo(=s2({tgT*m;{-^{zG~8U0`t@l=G%ogR+z;?IIrCgv zCBOl4t)Io&(S^t5AHO)^+lsK0<(8M0M0a_Et_8c@ntd7m+Qa1j61+av`S%FyTc(zq zmPB_Z|2rA(Y&Zp6O~X1Db(P?zffC$64iiLuqw!Xj)6)t#-#D)fSa>W>V<0A4<08~l fOmwL9YQp~qy%dXL)Iql-00000NkvXXu0mjfLpSSA literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable/dialog_button_animation.xml b/IAP6Helper/src/main/res/drawable/dialog_button_animation.xml new file mode 100644 index 000000000..7ed940974 --- /dev/null +++ b/IAP6Helper/src/main/res/drawable/dialog_button_animation.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IAP6Helper/src/main/res/drawable/dialog_full_holo_light.9.png b/IAP6Helper/src/main/res/drawable/dialog_full_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..e134c41a08952c062f799b69db689233f513cc62 GIT binary patch literal 2237 zcmaKudpHy98^gsxb*YA(tANTWI_jBFPbA7(|^W69KN)Wjf$_-W@yB9L$0r8Ho&vZBhDXO6V34?d2_^<+21Z7XD+nk6Aa=;f!48+? zzfkRztvU#DoVIcslP$0}m6k1o?NOYz1?H4E)E8$sxVt-mZ55D6r2})QJ!dMLv-52I z^0KQAnY>&9Kq%4~T3XgusO%NX7vHTHueUUL*BCSp4NhbVp5LMe1i;A2F=K0+uHmM@ zV;qYlflzMTctb{3%KB$YN~x)pmim?5GChuZUG~c!&z0TKO0c`9T^hpB;ZM+h%1m8y zUQOY?7X_4V({7EpR!O}DHaDzdbbs1WO#?~4#dxh{c}r?HjCtc0s-T@x0>6=}P(%t0 z@>cc+dL#W*nVeZ&-u{G4OYi~X%q!OhND(S0AZ$2gFNN!Icu1rL8Z8#DGRDEt8#=_J zdE%kV^bQ5jhqV_QPNI9VuXzf1tep{|2F5~xP!%ZXb-r)Dul(qH9AZE)nvij@dPd721lcd;ry$4_H|vxxVIZj=6WO^VFuq?k9X zOI4bfb8M8WJOmq>qg8NGD3m|ClwPK*^6Jk_Nu@p*k;_v5&{qR82YM2}&cAh5QByOh zF$wL%J?-yzpLo^ac>d$;?0v!R&NE=D*VR_faGcYoXeoWcMV7JZG2c2qK0dKAlb)Vl zkd`Ju*FNr2&_$Nn&YhkFe#mti@oPU2PRpVVX3ylG#U7M3?3IH(x_R?csUyw}bJ^ys zM0clI-(BNZq&8TyGf)%4He+9x{f`Q{rFfyY7JIIpvmFOn8)Koe;jCq?mEw^NNq?3)ZBw6~n}PK(9x)V*OO^Dr%_)>j*Rq@O!+xE_sJUQ;Pjj7i>lXBFbWUZl?-7*Z?SoEy`n-KRoE1AZ}8I#JGn(|?O79RH|+A? z$XKdo4DST6e+IPHQo?BN=<2@vmXj2==DsxvH{eUq(H%iPa=!%Gfie*T4RCt=;+~}L z3j3jB97zs#2en+}7wTUUweINApjfjOikf-Ss|}9v&wzilJVMlqzY7D&LCbq6Nn6wG zOXf*SGiung;t+kA7GhyC5S>LE!K0=q%$XF}aL<$RKdvrlK_tTcV%}|bqqQv{G~)Su2gru#h_)Vt zhP4@fuYR|Nl|gadxTe3YyVkYcU8L?-lVP$X4yhR;Z<{G#N8pY}l0HuYCVYy`Wkb0G z6B84#SRNW)nEuh|yG04gnAQuY_}!142_Q?W0vn-tL?0_Xb846oTmZ*U!kB8W)zJ|w z$jpzP1aI%5+lmLhw(k7#Wv`M#927mp9G6Lr*uqd^CA`E6`pN1dWage0|lm zF>1X1eowi+FN$&Ingu-@Yz1&JQyhdirWCtLER`JyPK*$Vew&q)Ah_4;3tqe zC_p&?Gy#Gu!+~%WIOqwij3nqcDFlT*RqP{>?ftk4_cEV2kPJ0koiOIiT&n1~G@ zP2=Zp>r;9yg5+LJx-#Cd}5QJD3jl?e)XV~p8kl8$m$R0nq9rn9R*h| zjg|zoBI{Db<-h5y?PfW!Z-Qb}T;>F)HK*m%d(NFsS;R?56Vl{=HKQCcI#YiO>H9lm zwwhl{`r3)23O#9g-%FB(%dO8rzT8%L9CWyHC?C38d%bN5GkKDZ-!f-WD1qi^$k?y$%eTz z7j6qJ&ssRYKTxxFO1CO8KP~6Tpr-nNXV4Y3vumG;R@M*M89i-$+&mThV12)p^zBum z2V01V2sJ*G=aT;*xZ>8zHgz@iU*cR}@U+iJrAEYw0%at^InU`jmBc0Gj$mqov;}c5 zc*iwr`uNvXtW({iZlFlTL>?cm32~l^=B^(j`J?G>UW@)nZ tq-{U=1!Wb^*#-af=LOoQuclYGB+CP&9ybzGmH594fD;nq(1Q4l^fyGZ3LO9d literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/drawable/dialog_radius_dark.xml b/IAP6Helper/src/main/res/drawable/dialog_radius_dark.xml new file mode 100644 index 000000000..9efa7d341 --- /dev/null +++ b/IAP6Helper/src/main/res/drawable/dialog_radius_dark.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/IAP6Helper/src/main/res/drawable/dialog_radius_light.xml b/IAP6Helper/src/main/res/drawable/dialog_radius_light.xml new file mode 100644 index 000000000..033283fa6 --- /dev/null +++ b/IAP6Helper/src/main/res/drawable/dialog_radius_light.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/IAP6Helper/src/main/res/drawable/progress_dialog_animation_dark.xml b/IAP6Helper/src/main/res/drawable/progress_dialog_animation_dark.xml new file mode 100644 index 000000000..b16189a7a --- /dev/null +++ b/IAP6Helper/src/main/res/drawable/progress_dialog_animation_dark.xml @@ -0,0 +1,5 @@ + + diff --git a/IAP6Helper/src/main/res/drawable/progress_dialog_animation_light.xml b/IAP6Helper/src/main/res/drawable/progress_dialog_animation_light.xml new file mode 100644 index 000000000..3279b8598 --- /dev/null +++ b/IAP6Helper/src/main/res/drawable/progress_dialog_animation_light.xml @@ -0,0 +1,5 @@ + + diff --git a/IAP6Helper/src/main/res/drawable/progressbar_middle.xml b/IAP6Helper/src/main/res/drawable/progressbar_middle.xml new file mode 100644 index 000000000..0dd4e4119 --- /dev/null +++ b/IAP6Helper/src/main/res/drawable/progressbar_middle.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/IAP6Helper/src/main/res/drawable/tw_widget_progressbar_effect_holo_light.png b/IAP6Helper/src/main/res/drawable/tw_widget_progressbar_effect_holo_light.png new file mode 100644 index 0000000000000000000000000000000000000000..f8e90af625e08d13a7c418582e7f1239de90bbde GIT binary patch literal 3462 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 literal 0 HcmV?d00001 diff --git a/IAP6Helper/src/main/res/layout/dialog_dark.xml b/IAP6Helper/src/main/res/layout/dialog_dark.xml new file mode 100644 index 000000000..448730a03 --- /dev/null +++ b/IAP6Helper/src/main/res/layout/dialog_dark.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + +