All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.onepf.opfiab.samsung.SamsungUtils Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012-2015 One Platform Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.onepf.opfiab.samsung;

import android.accounts.AccountManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.Signature;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.json.JSONException;
import org.json.JSONObject;
import org.onepf.opfiab.model.billing.Purchase;
import org.onepf.opfiab.model.billing.SkuDetails;
import org.onepf.opfiab.model.billing.SkuType;
import org.onepf.opfiab.model.event.billing.Status;
import org.onepf.opfiab.samsung.model.ItemType;
import org.onepf.opfiab.samsung.model.SamsungPurchase;
import org.onepf.opfiab.samsung.model.SamsungPurchasedItem;
import org.onepf.opfiab.samsung.model.SamsungSkuDetails;
import org.onepf.opfiab.util.OPFIabUtils;
import org.onepf.opfutils.OPFChecks;
import org.onepf.opfutils.OPFLog;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import static android.Manifest.permission.GET_ACCOUNTS;
import static org.onepf.opfiab.samsung.SamsungBillingProvider.NAME;


@SuppressWarnings({"ClassWithTooManyMethods", "PMD.GodClass"})
public final class SamsungUtils {

    private static final int BILLING_SIGNATURE_HASHCODE = 0x7a7eaf4b;
    private static final String BILLING_PACKAGE_NAME = "com.sec.android.iap";
    private static final String ACCOUNT_ACTIVITY = "com.sec.android.iap.activity.AccountActivity";
    private static final String PURCHASE_ACTIVITY = "com.sec.android.iap.activity.PaymentMethodListActivity";
    private static final String INSTALL_URI = "samsungapps://ProductDetail/com.sec.android.iap";
    private static final String ACCOUNT_TYPE_SAMSUNG = "com.osp.app.signin";

    private static final String KEY_TYPE = "mType";
    private static final String KEY_HAS_MORE = "hasMore";

    private static final String KEY_THIRD_PARTY = "THIRD_PARTY_NAME";
    private static final String KEY_STATUS_CODE = "STATUS_CODE";
    private static final String KEY_ERROR_STRING = "ERROR_STRING";
    private static final String KEY_IAP_UPGRADE_URL = "IAP_UPGRADE_URL";
    private static final String KEY_ITEM_GROUP_ID = "ITEM_GROUP_ID";
    private static final String KEY_ITEM_ID = "ITEM_ID";
    private static final String KEY_RESULT_LIST = "RESULT_LIST";
    private static final String KEY_RESULT_OBJECT = "RESULT_OBJECT";

    private static final ThreadLocal DATE_FORMAT = new ThreadLocal() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyyMMdd", Locale.getDefault());
        }
    };


    private SamsungUtils() {
        throw new IllegalStateException();
    }

    public static boolean checkSignature(@NonNull final Context context) {
        final Signature[] signatures = OPFIabUtils
                .getPackageSignatures(context, BILLING_PACKAGE_NAME);
        for (final Signature signature : signatures) {
            if (signature.hashCode() == BILLING_SIGNATURE_HASHCODE) {
                return true;
            }
        }
        OPFLog.e("Samsung signature check failed.");
        return false;
    }

    public static boolean hasSamsungAccount(@NonNull final Context context) {
        if (!OPFChecks.hasPermission(context, GET_ACCOUNTS)) {
            return true;
        }
        final Object service = context.getSystemService(Context.ACCOUNT_SERVICE);
        final AccountManager accountManager = (AccountManager) service;
        return accountManager.getAccountsByType(ACCOUNT_TYPE_SAMSUNG).length > 0;
    }

    @SuppressWarnings("PMD.MissingBreakInSwitch")
    @Nullable
    public static Status handleError(@NonNull final Context context,
                                     @Nullable final Bundle bundle) {
        final Response response = getResponse(bundle);
        if (response == Response.ERROR_NONE) {
            return null;
        }
        if (bundle == null || response == null) {
            return Status.UNKNOWN_ERROR;
        }
        OPFLog.e("Response %s: %s", response, getErrorString(bundle));
        switch (response) {
            case PAYMENT_IS_CANCELED:
                return Status.USER_CANCELED;
            case ERROR_ALREADY_PURCHASED:
                return Status.ITEM_ALREADY_OWNED;
            case ERROR_PRODUCT_DOES_NOT_EXIST:
            case ERROR_ITEM_GROUP_ID_DOES_NOT_EXIST:
                return Status.ITEM_UNAVAILABLE;
            case ERROR_NEED_APP_UPGRADE:
                SamsungUtils.promptUpgrade(context, bundle);
            case ERROR_NETWORK_NOT_AVAILABLE:
            case ERROR_CONNECT_TIMEOUT:
            case ERROR_SOCKET_TIMEOUT:
                return Status.SERVICE_UNAVAILABLE;
            default:
                return Status.UNKNOWN_ERROR;
        }
    }

    public static void promptInstall(@NonNull final Context context) {
        final Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(INSTALL_URI));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
        }

        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException exception) {
            OPFLog.e("", exception);
        }
    }

    public static void promptUpgrade(@NonNull final Context context,
                                     @Nullable final Bundle bundle) {
        final String uri;
        if (bundle == null || (uri = bundle.getString(KEY_IAP_UPGRADE_URL)) == null) {
            OPFLog.e("No upgrade url.");
            return;
        }

        final Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(uri));
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException exception) {
            OPFLog.e("Failed to open upgrade activity", exception);
        }
    }

    @NonNull
    public static String getNowDate() {
        //noinspection AccessToNonThreadSafeStaticField
        return DATE_FORMAT.get().format(new Date());
    }

    @Nullable
    public static Date parseDate(@Nullable final String date) {
        if (date == null) {
            return null;
        }
        try {
            return DATE_FORMAT.get().parse(date);
        } catch (ParseException e) {
            return null;
        }
    }

    @NonNull
    public static Intent getAccountIntent() {
        final Intent intent = new Intent();
        final ComponentName component = new ComponentName(BILLING_PACKAGE_NAME, ACCOUNT_ACTIVITY);
        intent.setComponent(component);
        return intent;
    }

    @NonNull
    public static Intent getPurchaseIntent(@NonNull final Context context,
                                           @NonNull final String groupId,
                                           @NonNull final String itemId) {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);

        final ComponentName component = new ComponentName(BILLING_PACKAGE_NAME, PURCHASE_ACTIVITY);
        intent.setComponent(component);

        final Bundle bundle = new Bundle();
        final String packageName = context.getPackageName();
        bundle.putString(KEY_THIRD_PARTY, packageName);
        bundle.putString(KEY_ITEM_GROUP_ID, groupId);
        bundle.putString(KEY_ITEM_ID, itemId);
        intent.putExtras(bundle);

        return intent;
    }

    @NonNull
    public static ItemType getItemType(@NonNull final JSONObject jsonObject) throws JSONException {
        final String type = jsonObject.getString(KEY_TYPE);
        final ItemType itemType = ItemType.fromCode(type);
        if (itemType == null) {
            throw new JSONException("Unrecognized item type: " + type);
        }
        return itemType;
    }

    @Nullable
    public static Response getResponse(@Nullable final Bundle bundle) {
        if (bundle != null && bundle.containsKey(KEY_STATUS_CODE)) {
            final int code = bundle.getInt(KEY_STATUS_CODE);
            return Response.fromCode(code);
        }
        return null;
    }

    @Nullable
    public static String getErrorString(@Nullable final Bundle bundle) {
        if (bundle != null && bundle.containsKey(KEY_ERROR_STRING)) {
            return bundle.getString(KEY_ERROR_STRING);
        }
        return null;
    }

    @Nullable
    public static Collection getItems(@Nullable final Bundle bundle) {
        final List items;
        if (bundle == null || (items = bundle.getStringArrayList(KEY_RESULT_LIST)) == null) {
            return null;
        }

        if (items.isEmpty()) {
            Collections.emptyList();
        }

        return items;
    }

    @Nullable
    public static Collection getPurchasedItems(@Nullable final Bundle bundle,
                                                         final boolean loadConsumable) {
        final Collection items = getItems(bundle);
        if (items == null) {
            return null;
        }

        final Collection purchases = new ArrayList<>();
        for (final String item : items) {
            try {
                final SamsungPurchasedItem purchasedItem = new SamsungPurchasedItem(item);
                if (loadConsumable || purchasedItem.getItemType() != ItemType.CONSUMABLE) {
                    purchases.add(SamsungUtils.convertPurchasedItem(purchasedItem));
                }
            } catch (JSONException exception) {
                OPFLog.e("Filed to decode Samsung inventory item.", exception);
            }
        }

        return purchases;
    }

    @Nullable
    public static Collection getSkusDetails(@Nullable final Bundle bundle,
                                                        @NonNull final Collection skus) {
        final Collection items = getItems(bundle);
        if (items == null) {
            return null;
        }

        final Collection skusDetails = new ArrayList<>(skus.size());
        final Collection unloadedItems = new ArrayList<>(skus);
        for (final String item : items) {
            try {
                final SamsungSkuDetails skuDetails = new SamsungSkuDetails(item);
                final String sku = skuDetails.getItemId();
                if (unloadedItems.contains(sku)) {
                    skusDetails.add(convertSkuDetails(skuDetails));
                    unloadedItems.remove(sku);
                }
            } catch (JSONException exception) {
                OPFLog.e("Filed to decode Samsung sku details.", exception);
            }
        }
        for (final String sku : unloadedItems) {
            skusDetails.add(new SkuDetails(sku));
        }

        return skusDetails;
    }

    @Nullable
    public static SamsungPurchase getPurchase(@Nullable final Bundle bundle) {
        final String item;
        if (bundle == null || (item = bundle.getString(KEY_RESULT_OBJECT)) == null) {
            return null;
        }
        try {
            return new SamsungPurchase(item);
        } catch (JSONException exception) {
            OPFLog.e("Failed to decode Samsung purchase.", exception);
        }
        return null;
    }

    @Nullable
    public static Boolean getHasMore(@Nullable final Bundle bundle) {
        if (bundle == null || !bundle.containsKey(KEY_HAS_MORE)) {
            return null;
        }
        return bundle.getBoolean(KEY_HAS_MORE);
    }

    @Nullable
    public static Bundle putHasMore(@Nullable final Bundle bundle, final boolean hasMore) {
        if (bundle == null) {
            return null;
        }
        bundle.putBoolean(KEY_HAS_MORE, hasMore);
        return bundle;
    }

    @NonNull
    public static SkuType convertType(@NonNull final ItemType itemType) {
        switch (itemType) {
            case CONSUMABLE:
                return SkuType.CONSUMABLE;
            case NON_CONSUMABLE:
                return SkuType.ENTITLEMENT;
            case SUBSCRIPTION:
                return SkuType.SUBSCRIPTION;
            default:
                return SkuType.UNKNOWN;
        }
    }

    @NonNull
    public static SkuDetails convertSkuDetails(@NonNull final SamsungSkuDetails samsungSkuDetails) {
        return new SkuDetails.Builder(samsungSkuDetails.getItemId())
                .setOriginalJson(samsungSkuDetails.getOriginalJson())
                .setType(convertType(samsungSkuDetails.getItemType()))
                .setTitle(samsungSkuDetails.getName())
                .setDescription(samsungSkuDetails.getDescription())
                .setPrice(samsungSkuDetails.getPriceString())
                .setProviderName(NAME)
                .build();
    }

    @NonNull
    public static Purchase convertPurchasedItem(@NonNull final SamsungPurchasedItem purchasedItem) {
        final Date endDate = purchasedItem.getSubscriptionEndDate();
        return new Purchase.Builder(purchasedItem.getItemId())
                .setOriginalJson(purchasedItem.getOriginalJson())
                .setType(convertType(purchasedItem.getItemType()))
                .setToken(purchasedItem.getPurchaseId())
                .setPurchaseTime(purchasedItem.getPurchaseDate().getTime())
                .setCanceled(endDate != null && endDate.before(new Date()))
                .setProviderName(NAME)
                .build();
    }

    @NonNull
    public static Purchase convertPurchase(@NonNull final SamsungPurchase purchase,
                                           @NonNull final SkuType skuType) {
        return new Purchase.Builder(purchase.getItemId())
                .setOriginalJson(purchase.getOriginalJson())
                .setType(skuType)
                .setToken(purchase.getPurchaseId())
                .setPurchaseTime(purchase.getPurchaseDate().getTime())
                .setProviderName(NAME)
                .build();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy