purchasableitemBase.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /**
  2. * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
  3. * All rights reserved.
  4. *
  5. * For the applicable distribution terms see the license.txt -file, included in
  6. * the distribution.
  7. */
  8. #include <iapclient.h>
  9. #include <QDebug>
  10. #include <QApplication>
  11. #include <QFile>
  12. #include <QDir>
  13. #include "purchasableitembase.h"
  14. #include "declarativepurchaselistmodel.h"
  15. #define TICKETFOLDERNAME "tickets"
  16. Q_DECLARE_METATYPE(IAPClient::ProductList) //to be able to transfer data this type with Qt::QueuedConnection
  17. Q_DECLARE_METATYPE(IAPClient::ProductDataList)
  18. // local function declaration
  19. bool isTheSameProduct(IAPClient::ProductDataHash& left, IAPClient::ProductData& right);
  20. PurchasableItemBase::PurchasableItemBase(DeclarativePurchaseListModel& model, QString& productID, QString& productUrl) :
  21. QObject(&model), //parent
  22. m_model(&model),
  23. m_isBusy(false),
  24. m_isKnown(false),
  25. m_unlocked_icon(NULL),
  26. m_buy_icon(NULL),
  27. m_notready_icon(NULL),
  28. m_productUrl(productUrl)
  29. {
  30. m_productMetadata.productId = productID;
  31. // connect IAP API's signals to app's slots
  32. IAPClient *client = &m_model->client();
  33. qRegisterMetaType<IAPClient::ProductDataHash>("IAPClient::ProductDataHash");
  34. connect(client, SIGNAL(productDataReceived( int, QString, IAPClient::ProductDataHash)),
  35. this, SLOT(productDataReceived(int, QString, IAPClient::ProductDataHash)), Qt::QueuedConnection);
  36. connect(client, SIGNAL(purchaseCompleted( int , QString, QString)),
  37. this, SLOT(purchaseCompleted( int , QString, QString)),Qt::QueuedConnection);
  38. connect(client, SIGNAL(purchaseFlowFinished(int)),
  39. this, SLOT(purchaseFlowFinished(int)), Qt::QueuedConnection);
  40. connect(client, SIGNAL(restorationCompleted (int , QString , QString)),
  41. this, SLOT(restorationCompleted (int , QString , QString)), Qt::QueuedConnection);
  42. //initialize data
  43. m_productMetadata.dataRequestResult = "Pending";
  44. m_productMetadata.drmProtection = IAPClient::NokiaDrm;
  45. fetchMetadata();
  46. }
  47. PurchasableItemBase::~PurchasableItemBase()
  48. {
  49. delete m_unlocked_icon;
  50. m_unlocked_icon = NULL;
  51. delete m_buy_icon;
  52. m_buy_icon = NULL;
  53. delete m_notready_icon;
  54. m_notready_icon = NULL;
  55. }
  56. QVariant PurchasableItemBase::metadata(int role) const
  57. {
  58. switch(role)
  59. {
  60. case ProductIdRole:
  61. return m_productMetadata.productId;
  62. case DataReqResultRole:
  63. return m_productMetadata.dataRequestResult;
  64. case TitleRole:
  65. return m_productMetadata.title;
  66. case ShortDescriptionRole:
  67. return m_productMetadata.shortDescription;
  68. case LongDescriptionRole:
  69. return m_productMetadata.longDescription;
  70. case PriceRole:
  71. return m_productMetadata.price;
  72. case DrmProtectionRole:
  73. return ((m_productMetadata.drmProtection == IAPClient::NokiaDrm) ? true : false);
  74. case IsMetadataKnown:
  75. return m_isKnown;
  76. case IsBusy:
  77. return m_isBusy;
  78. case IsActivated:
  79. return (isActivated());
  80. default:
  81. break;
  82. }
  83. return QVariant();
  84. }
  85. bool PurchasableItemBase::setMetadata(const QVariant & value, int role)
  86. {
  87. bool result = true;
  88. switch(role)
  89. {
  90. case ProductIdRole:
  91. m_productMetadata.productId = value.toString();
  92. break;
  93. case DataReqResultRole:
  94. m_productMetadata.dataRequestResult = value.toString();
  95. break;
  96. case TitleRole:
  97. m_productMetadata.title = value.toString();
  98. break;
  99. case ShortDescriptionRole:
  100. m_productMetadata.shortDescription = value.toString();
  101. break;
  102. case LongDescriptionRole:
  103. m_productMetadata.longDescription = value.toString();
  104. break;
  105. case PriceRole:
  106. m_productMetadata.price = value.toString();
  107. break;
  108. case DrmProtectionRole:
  109. m_productMetadata.drmProtection = (value.toBool()) ? IAPClient::NokiaDrm : IAPClient::OtherDrm;
  110. break;
  111. case IsMetadataKnown: //read-only properties
  112. case IsBusy:
  113. m_isBusy = value.toBool();
  114. break;
  115. case IsActivated:
  116. // cannot be unlocked by this call but can be locked
  117. if(value.toBool())
  118. result = false;
  119. else
  120. deactivate();
  121. break;
  122. default:
  123. result = false;
  124. break;
  125. }
  126. return result;
  127. }
  128. void PurchasableItemBase::deactivate()
  129. {
  130. delete m_unlocked_icon;
  131. m_unlocked_icon = NULL;
  132. }
  133. bool PurchasableItemBase::isMetaDataKnown() const
  134. {
  135. return m_isKnown;
  136. }
  137. bool PurchasableItemBase::isBusy()
  138. {
  139. return m_isBusy;
  140. }
  141. bool PurchasableItemBase::isActivated() const
  142. {
  143. return (m_unlocked_icon != NULL);
  144. }
  145. void PurchasableItemBase::fetchMetadata()
  146. {
  147. qDebug(__FUNCTION__);
  148. if(setBusy())
  149. {
  150. m_requestId = m_model->client().getProductData(m_productMetadata.productId);
  151. }
  152. }
  153. void PurchasableItemBase::purchase()
  154. {
  155. qDebug(__FUNCTION__);
  156. if(setBusy())
  157. {
  158. m_requestId = m_model->client().purchaseProduct(m_productMetadata.productId, IAPClient::NoForcedRestoration);
  159. }
  160. }
  161. void PurchasableItemBase::restore()
  162. {
  163. qDebug(__FUNCTION__);
  164. if(setBusy())
  165. {
  166. qDebug() << "restoreProduct : " << m_productMetadata.productId;
  167. m_requestId = m_model->client().restoreProduct(m_productMetadata.productId);
  168. }
  169. }
  170. void PurchasableItemBase::productDataReceived(int requestId, QString status,
  171. IAPClient::ProductDataHash productData)
  172. {
  173. if(requestId != m_requestId)
  174. return;
  175. qDebug(__FUNCTION__);
  176. m_model->beginModelUpdate();
  177. m_isBusy = false;
  178. m_isKnown = true;
  179. IAPClient::DrmType type = m_productMetadata.drmProtection;
  180. QString productId = m_productMetadata.productId;
  181. m_productMetadata.title = productData.value("info").toString();
  182. m_productMetadata.shortDescription = productData.value("shortdescription").toString();
  183. m_productMetadata.longDescription = productData.value("description").toString();
  184. m_productMetadata.price = productData.value("price").toString();
  185. m_productMetadata.dataRequestResult = productData.value("result").toString();
  186. m_productMetadata.drmProtection = type; //preserve DRM type
  187. m_productMetadata.productId = productId; //preserve Product ID
  188. if(isPurchased())
  189. setUnlocked(NULL);
  190. m_model->commitModelUpdate();
  191. }
  192. void PurchasableItemBase::purchaseCompleted(int requestId, QString status, QString purchaseTicket)
  193. {
  194. if(requestId != m_requestId)
  195. return;
  196. qDebug(__FUNCTION__);
  197. m_model->beginModelUpdate();
  198. m_isBusy = false;
  199. if(status.compare("OK", Qt::CaseSensitive) == 0)
  200. {
  201. setUnlocked(&purchaseTicket);
  202. }
  203. m_model->commitModelUpdate();
  204. }
  205. void PurchasableItemBase::purchaseFlowFinished(int requestId)
  206. {
  207. if(requestId != m_requestId)
  208. return;
  209. qDebug(__FUNCTION__);
  210. m_isBusy = false;
  211. }
  212. void PurchasableItemBase::restorationCompleted(int requestId, QString status, QString purchaseTicket)
  213. {
  214. if(requestId != m_requestId)
  215. return;
  216. qDebug(__FUNCTION__);
  217. m_model->beginModelUpdate();
  218. m_isBusy = false;
  219. if(status.compare("OK", Qt::CaseSensitive) == 0)
  220. {
  221. setUnlocked(&purchaseTicket);
  222. }
  223. m_model->commitModelUpdate();
  224. }
  225. void PurchasableItemBase::restorationFlowFinished(int requestId)
  226. {
  227. if(requestId != m_requestId)
  228. return;
  229. qDebug(__FUNCTION__);
  230. m_isBusy = false;
  231. }
  232. QImage& PurchasableItemBase::stateIcon() const
  233. {
  234. if(m_unlocked_icon)
  235. return *m_unlocked_icon;
  236. else if(m_isKnown)
  237. return *m_buy_icon;
  238. else
  239. return *m_notready_icon;
  240. }
  241. bool PurchasableItemBase::setBusy()
  242. {
  243. if(isActivated())
  244. return false; // already unlocked, no remote operation possible
  245. if(m_isBusy)
  246. {
  247. qDebug() << "item is busy. you can set only one request at time on the item";
  248. return false;
  249. }
  250. m_model->beginModelUpdate();
  251. m_isBusy = true;
  252. m_model->commitModelUpdate();
  253. return true;
  254. }
  255. void PurchasableItemBase::saveTicket(QString* purchaseTicket)
  256. {
  257. if(!purchaseTicket)
  258. return;
  259. QString privatedir(getTicketDir());
  260. if(!QDir(privatedir).exists())
  261. QDir().mkdir(privatedir);
  262. QFile file(getTicketUri());
  263. if(file.open(QIODevice::WriteOnly))
  264. {
  265. QDataStream out(&file);
  266. out << *purchaseTicket;
  267. file.close();
  268. }
  269. else
  270. {
  271. qDebug() << "PurchasableItemBase::testModeSaveTicket >>> Cannot open file for writing: ";
  272. }
  273. }
  274. bool PurchasableItemBase::readTicket()
  275. {
  276. return (QFile(getTicketUri()).exists());
  277. }
  278. QString PurchasableItemBase::getTicketUri()
  279. {
  280. QString fname(QApplication::applicationDirPath());
  281. fname.append("/");
  282. fname.append(TICKETFOLDERNAME);
  283. fname.append("/");
  284. fname.append(m_productMetadata.productId);
  285. fname.append(".ticket");
  286. return fname;
  287. }
  288. QString PurchasableItemBase::getTicketDir()
  289. {
  290. QString fname(QApplication::applicationDirPath());
  291. fname.append("/");
  292. fname.append(TICKETFOLDERNAME);
  293. return fname;
  294. }
  295. bool PurchasableItemBase::isIncluded(IAPClient::ProductDataList& list)
  296. {
  297. foreach(IAPClient::ProductDataHash item, list)
  298. {
  299. if(isTheSameProduct(item, m_productMetadata))
  300. return true;
  301. }
  302. return false;
  303. }
  304. bool isTheSameProduct(IAPClient::ProductDataHash& left, IAPClient::ProductData& right)
  305. {
  306. return (left.value("id").toString().compare(right.productId) == 0);
  307. }