Java tutorial
/* * Copyright 2014 serso aka se.solovyev * * 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. * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Contact details * * Email: se.solovyev@gmail.com * Site: http://se.solovyev.org */ package kz.tanikin.inapppurchase2; import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; import org.solovyev.android.checkout.ActivityCheckout; import org.solovyev.android.checkout.BillingRequests; import org.solovyev.android.checkout.Checkout; import org.solovyev.android.checkout.Inventory; import org.solovyev.android.checkout.Purchase; import org.solovyev.android.checkout.RequestListener; import org.solovyev.android.checkout.ResponseCodes; import org.solovyev.android.checkout.Sku; import java.util.Comparator; import static android.view.animation.AnimationUtils.loadAnimation; import static org.solovyev.android.checkout.ProductTypes.IN_APP; public class SkusFragment extends Fragment { protected ActivityCheckout checkout; private boolean listShown; protected ListView listView; protected ProgressBar progressBar; protected TextView emptyView; protected TextView titleView; protected Inventory inventory; private ArrayAdapter<SkuUi> adapter; String tag = "SkusFragment"; @Override public void onAttach(Activity activity) { super.onAttach(activity); checkout = ((MainActivity) activity).getCheckout(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); inventory = checkout.loadInventory(); for (Inventory.Product product : inventory.getProducts()) { Log.i(tag, product.getPurchases() + " produ"); } checkout.createPurchaseFlow(new PurchaseListener()); } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { final View view = inflater.inflate(R.layout.fragment_list, container, false); titleView = (TextView) view.findViewById(R.id.list_title); listView = (ListView) view.findViewById(android.R.id.list); progressBar = (ProgressBar) view.findViewById(android.R.id.progress); emptyView = (TextView) view.findViewById(android.R.id.empty); adapter = new SkusAdapter(inflater.getContext()); listView.setAdapter(adapter); listView.setOnItemClickListener(new OnSkuClickListener()); titleView.setText(R.string.items_for_purchase); emptyView.setText(R.string.skus_empty); Log.i(tag, adapter.getCount() + ""); return view; } public void setListShown(boolean shown, boolean animate) { if (listShown == shown) { return; } listShown = shown; if (shown) { final View view = listView.getCount() > 0 ? listView : emptyView; if (animate) { progressBar.startAnimation(loadAnimation(getActivity(), android.R.anim.fade_out)); view.startAnimation(loadAnimation(getActivity(), android.R.anim.fade_in)); } progressBar.setVisibility(View.GONE); view.setVisibility(View.VISIBLE); } else { final View view = listView.getVisibility() == View.VISIBLE ? listView : emptyView; if (animate) { progressBar.startAnimation(loadAnimation(getActivity(), android.R.anim.fade_in)); view.startAnimation(loadAnimation(getActivity(), android.R.anim.fade_out)); } progressBar.setVisibility(View.VISIBLE); view.setVisibility(View.INVISIBLE); } } public void setListShown(boolean shown) { setListShown(shown, true); } public void setListShownNoAnimation(boolean shown) { setListShown(shown, false); } @Override public void onDestroy() { checkout.destroyPurchaseFlow(); super.onDestroy(); } private class PurchaseListener extends BaseRequestListener<Purchase> { @Override public void onSuccess(Purchase purchase) { onPurchased(); } private void onPurchased() { // let's update purchase information in local inventory inventory.load().whenLoaded(new InventoryLoadedListener()); Toast.makeText(getActivity(), R.string.msg_thank_you_for_purchase, Toast.LENGTH_SHORT).show(); Log.i(tag, getString(R.string.msg_thank_you_for_purchase)); } @Override public void onError(int response, Exception e) { // it is possible that our data is not synchronized with data on Google Play => need to handle some errors if (response == ResponseCodes.ITEM_ALREADY_OWNED) { onPurchased(); } else { super.onError(response, e); } } } private class OnSkuClickListener implements AdapterView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { final SkuUi sku = adapter.getItem(position); purchase(sku); } } private void purchase(final SkuUi skuUi) { if (!skuUi.isPurchased()) { purchase(skuUi.sku); } else { consume(skuUi.token, new ConsumeListener()); } } private void consume(final String token, final RequestListener<Object> onConsumed) { checkout.whenReady(new Checkout.ListenerAdapter() { @Override public void onReady(BillingRequests requests) { requests.consume(token, onConsumed); } }); } private void purchase(final Sku sku) { checkout.whenReady(new Checkout.ListenerAdapter() { @Override public void onReady(BillingRequests requests) { requests.purchase(sku, null, checkout.getPurchaseFlow()); } }); } private static class SkuComparator implements Comparator<SkuUi> { @Override public int compare(SkuUi l, SkuUi r) { return l.sku.title.compareTo(r.sku.title); } } private class InventoryLoadedListener implements Inventory.Listener { @Override public void onLoaded(Inventory.Products products) { final Inventory.Product product = products.get(IN_APP); adapter.setNotifyOnChange(false); adapter.clear(); if (product.supported) { for (Sku sku : product.getSkus()) { final Purchase purchase = product.getPurchaseInState(sku, Purchase.State.PURCHASED); adapter.add(SkuUi.create(sku, purchase != null ? purchase.token : null)); } adapter.sort(new SkuComparator()); } else { emptyView.setText(R.string.billing_not_supported); } adapter.notifyDataSetChanged(); setListShown(true); } } private abstract class BaseRequestListener<R> implements RequestListener<R> { @Override public void onError(int response, Exception e) { // todo serso: add alert dialog or console } } private class ConsumeListener extends BaseRequestListener<Object> { @Override public void onSuccess(Object result) { onConsumed(); } private void onConsumed() { inventory.load().whenLoaded(new InventoryLoadedListener()); Toast.makeText(getActivity(), R.string.msg_item_consumed, Toast.LENGTH_SHORT).show(); } @Override public void onError(int response, Exception e) { // it is possible that our data is not synchronized with data on Google Play => need to handle some errors if (response == ResponseCodes.ITEM_NOT_OWNED) { onConsumed(); } else { super.onError(response, e); } } } }