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.
+ *
+ *
+ * This load owned product list by starting OwnedListActivity in this library, and the result will be sent to {@link OnGetOwnedListListener}
+ * Callback interface.
+ *
+ *
+ * This load item list by starting OwnedListActivity in this library, and the result will be sent to {@link OnConsumePurchasedItemsListener}
+ * Callback interface.
+ *
+ *
+ * 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.
+ *
+ * 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.
+ *