/* * Copyright © 2012 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.attractions.views; import com.nokia.example.attractions.Visual; import com.nokia.example.attractions.views.list.List; import com.nokia.example.attractions.views.list.NewGuideDrawer; import com.nokia.example.attractions.models.Guide; import com.nokia.example.attractions.network.NewGuidesOperation; import com.nokia.example.attractions.utils.UIUtils; import com.nokia.mid.payment.IAPClientPaymentException; import com.nokia.mid.payment.IAPClientPaymentListener; import com.nokia.mid.payment.IAPClientPaymentManager; import com.nokia.mid.payment.IAPClientProductData; import com.nokia.mid.payment.IAPClientUserAndDeviceData; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.Graphics; /** * View to display a list of purchasable guides */ public final class BuyGuidesView extends BaseView implements IAPClientPaymentListener { private static final String NEW_GUIDES_URL = "http://fn-iap-repo.cloudapp.net/api/touristattractions"; private static final String GUIDE_URL_PREFIX = NEW_GUIDES_URL + "/"; private final Command buyCmd = UIUtils.createCommand(UIUtils.BUY); private volatile String account = null; private volatile boolean loadingAccount = false; private volatile Vector guides = null; private volatile boolean loadingGuides = false; private final List guidesList; private final IAPClientPaymentManager manager; private volatile Guide purchasing = null; private Hashtable waitingProductData; private final Hashtable cache = new Hashtable(); BuyGuidesView() throws IAPClientPaymentException { guidesList = List.getList(new NewGuideDrawer(viewMaster, viewMaster. getDefaultThumbnailIcon(), cache), new List.Listener() { public void select(int focusedRowIndex) { selectGuide(focusedRowIndex); } }); manager = IAPClientPaymentManager.getIAPClientPaymentManager(); IAPClientPaymentManager.setIAPClientPaymentListener(this); } public final void resize(int x, int y, int width, int height) { super.resize(x, y, width, height); guidesList.resize(x, y, width, height); } public final void activate() { viewMaster.setTitle("Buy guide"); if (manager == null) { guides = new Vector(); } else if (account == null) { loadAccountAndGuides(); } else if (guides == null) { loadGuides(); } showGuides(); super.activate(); viewMaster.addCommand(backCmd); if (!viewMaster.hasPointerEvents()) { viewMaster.addCommand(buyCmd); } } private void showGuides() { if (guides == null || guides.isEmpty()) { return; } guidesList.setData(guides); guidesList.enable(); } public final void deactivate() { viewMaster.removeCommand(buyCmd); super.deactivate(); guidesList.disable(); cache.clear(); } public final void draw(final Graphics g) { if (!isActive()) { return; } if (guides == null || purchasing != null) { drawLoading(g); } else if (guides.isEmpty()) { drawNoGuides(g); } else { guidesList.draw(g); } } private void drawNoGuides(final Graphics g) { ViewMaster.drawBackground(g, getX(), getY(), getWidth(), getHeight(), false); g.setColor(Visual.LIST_PRIMARY_COLOR); g.setFont(Visual.MEDIUM_FONT); int y0 = getY() + getHeight() / 2 + g.getFont().getHeight() / 2; g.drawString("no guides", getX() + getWidth() / 2, y0, Graphics.BOTTOM | Graphics.HCENTER); } private void loadAccountAndGuides() { if (loadingAccount) { return; } loadingAccount = true; // For restoring guides user's account is needed int status = manager.getUserAndDeviceId( IAPClientPaymentManager.DEFAULT_AUTHENTICATION); if (status != IAPClientPaymentManager.SUCCESS) { showAlert("Authorization failure " + status, "Authorization failure", "Authorization process failed. " + getPaymentError(status)); viewMaster.setPreviousView(); loadingAccount = false; } } /** * @see IAPClientPaymentListener#userAndDeviceDataReceived(int, com.nokia.mid.payment.IAPClientUserAndDeviceData) */ public final void userAndDeviceDataReceived(int status, IAPClientUserAndDeviceData ud) { if (status == OK) { account = ud.getAccount(); loadGuides(); } else { showAlert("Authorization listener failure " + status, "Authorization failure", "Authorization process failed. " + getPaymentError(status)); viewMaster.setPreviousView(); } loadingAccount = false; } private void loadGuides() { if (loadingGuides) { return; } loadingGuides = true; new NewGuidesOperation(new NewGuidesOperation.Listener() { public void guidesReceived(Vector newGuides) { if (newGuides == null) { showAlert("Network failure", "Network failure", "Connecting network failed."); viewMaster.setPreviousView(); loadingGuides = false; } else { waitingProductData = new Hashtable(); for (int i = 0, length = newGuides.size(); i < length; i++) { Guide guide = (Guide) newGuides.elementAt(i); if (!data.getGuides().contains(guide)) { waitingProductData.put(guide.getId(), guide); guide.setUrl(GUIDE_URL_PREFIX + guide.getId()); guide.setAccount(account); } } loadProductData(); } } }, NEW_GUIDES_URL, account).start(); } private void loadProductData() { if (waitingProductData.isEmpty()) { waitingProductData = null; if (guides == null) { guides = new Vector(); loadingGuides = false; if (isActive()) { viewMaster.draw(); } } return; } String[] productIds = new String[waitingProductData.size()]; Enumeration e = waitingProductData.keys(); for (int i = 0; e.hasMoreElements(); i++) { productIds[i] = ((String) e.nextElement()); } int status = manager.getProductData(productIds); if (status != IAPClientPaymentManager.SUCCESS) { waitingProductData = null; showAlert("Metadata failure " + status, "Connection failure", "Loading new guides failed. " + getPaymentError(status)); viewMaster.setPreviousView(); loadingGuides = false; } } /** * @see IAPClientPaymentListener#productDataListReceived(int, com.nokia.mid.payment.IAPClientProductData[]) */ public final void productDataListReceived(int status, IAPClientProductData[] productDataList) { if (status == OK) { guides = new Vector(); for (int i = 0, size = productDataList.length; i < size; i++) { IAPClientProductData productData = productDataList[i]; if (productData.getProductId() != null) { Guide guide = (Guide) waitingProductData.remove(productData. getProductId()); String title = productData.getTitle(); if (title == null) { title = productData.getShortDescription(); } if (title == null) { title = "unknown"; } String price = productData.getPrice(); if (price == null) { price = "unknown"; } if (guide != null) { guide.setCity(title); guide.setPrice(price); guides.addElement(guide); } } } if (isActive()) { showGuides(); viewMaster.draw(); } } else { showAlert("Metadata listener failure " + status, "Connection failure", "Loading new guides failed. " + getPaymentError(status)); viewMaster.setPreviousView(); } waitingProductData = null; loadingGuides = false; } public final void restorableProductsReceived(int status, IAPClientProductData[] productDataList) { } public final void productDataReceived(int status, IAPClientProductData productData) { } private void selectGuide(int index) { if (purchasing != null) { return; } purchasing = (Guide) guides.elementAt(index); if (purchasing.isRestorable()) { // Restore guide from the backend guidePurchased(""); } else { // Purchase guide using Nokia Store int status = manager.purchaseProduct(purchasing.getId(), IAPClientPaymentManager.FORCED_AUTOMATIC_RESTORATION); if (status != IAPClientPaymentManager.SUCCESS) { purchasing = null; showAlert("Purchase failure " + status, "Purchase failure", "Purchase process failed. " + getPaymentError(status)); } } } /** * @see IAPClientPaymentListener#purchaseCompleted(int, java.lang.String) */ public final void purchaseCompleted(int status, String purchaseTicket) { switch (status) { case OK: guidePurchased(purchaseTicket); break; case RESTORABLE: guidePurchased(purchaseTicket == null ? "" : purchaseTicket); break; default: purchasing = null; showAlert("Purchase listener failure " + status, "Purchase failure", "Purchase process failed. " + getPaymentError(status)); break; } } /** * @see IAPClientPaymentListener#restorationCompleted(int, java.lang.String) */ public final void restorationCompleted(int status, String purchaseTicket) { switch (status) { case OK: guidePurchased(purchaseTicket); break; default: purchasing = null; showAlert("Restoration listener failure " + status, "Restoration failure", "Restoration failed. " + getPaymentError(status)); break; } } private void guidePurchased(String purchaseTicket) { if (purchasing == null) { return; } purchasing.setPurchaseTicket(purchaseTicket); guides.removeElement(purchasing); data.getGuides().addElement(purchasing); data.setCurrentGuideIndex(data.getGuides().indexOf(purchasing)); data.saveGuides(); purchasing = null; viewMaster.showAttractionsView(); } /** * @param code * @return Error string according to the code */ public final String getPaymentError(int code) { switch (code) { case IAPClientPaymentListener.NO_PMT_METHODS: return "No payment methods are set up in your Nokia account. " + "Please enable some of the methods to be able to " + "proceed."; case IAPClientPaymentListener.OVI_SIGN_IN_FAILED: return "Cannot sign in to your Nokia Account. Please check " + "your credentials."; case IAPClientPaymentListener.RESTORATION_DEVICE_LMT_EXCEEDED: return "Unfortunately the number of restorations allowed on " + "the device has exceeded limit."; case IAPClientPaymentListener.RESTORATION_LMT_EXCEEDED: return "Unfortunately the number of restorations allowed for " + "this item has exceeded limit."; case IAPClientPaymentListener.RESTORATION_FAILED: case IAPClientPaymentListener.RESTORATION_NOT_ALLOWED: return "It seems you haven't purchased the guide yet, and " + "therefore restoration is not" + "possible. Please, use the purchasing options."; case IAPClientPaymentListener.SMS_PMT_FAILED: return "Sending SMS has failed in operator payment."; default: return "There was a problem with Nokia Services. Please try " + "again later. If the problem persists, please " + "contact the application vendor."; } } public final void keyPressed(int keyCode) { handleKey(keyCode); } public final void keyRepeated(int keyCode) { handleKey(keyCode); } private void handleKey(int keyCode) { if (!isActive() || guides == null || guides.isEmpty()) { return; } switch (viewMaster.getGameAction(keyCode)) { case ViewMaster.UP: guidesList.focusUp(); viewMaster.forceDraw(); break; case ViewMaster.DOWN: guidesList.focusDown(); viewMaster.forceDraw(); break; case ViewMaster.FIRE: guidesList.select(); break; default: break; } } public final void commandAction(Command cmd) { if (cmd == buyCmd) { if (guides != null && !guides.isEmpty()) { guidesList.select(); } } else { super.commandAction(cmd); } } }