Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAndroidDonations.cpp
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: GPL-3.0-or-later
3 */
5
6#include "KisApplication.h"
7#include "kis_splash_screen.h"
8
9#include <QAndroidJniEnvironment>
10#include <QImage>
11#include <QTemporaryFile>
12#include <QtAndroid>
13
14// See DonationHelper.java for notes!
15
16namespace
17{
18void cleanupProductIconData(void *info)
19{
20 uint32_t *data = static_cast<uint32_t *>(info);
21 delete[] data;
22}
23
24QPixmap getProductIcon(const QAndroidJniObject &javaProduct)
25{
26 jint width = 256;
27 jint height = 256;
28
29 QAndroidJniObject pixelsArrayObject = javaProduct.callObjectMethod("getIconPixels", "(II)[I", width, height);
30 if (!pixelsArrayObject.isValid()) {
31 return QPixmap();
32 }
33
34 jintArray pixelsArray = static_cast<jintArray>(pixelsArrayObject.object());
35 if (!pixelsArray) {
36 return QPixmap();
37 }
38
39 QAndroidJniEnvironment env;
40 jsize length = env->GetArrayLength(pixelsArray);
41 if (length != jsize(width) * jsize(height)) {
42 return QPixmap();
43 }
44
45 jint *pixels = env->GetIntArrayElements(pixelsArray, nullptr);
46 if (!pixels) {
47 return QPixmap();
48 }
49
50 uint32_t *data = new uint32_t[length];
51 for (jsize i = 0; i < length; ++i) {
52 data[i] = uint32_t(pixels[i]);
53 }
54
55 env->ReleaseIntArrayElements(pixelsArray, pixels, 0);
56
57 QPixmap pixmap;
58 if (!pixmap.convertFromImage(QImage(reinterpret_cast<uchar *>(data),
59 int(width),
60 int(height),
61 qsizetype(width) * qsizetype(4),
62 QImage::Format_ARGB32,
63 cleanupProductIconData,
64 data))) {
65 return QPixmap();
66 }
67
68 return pixmap;
69}
70} // namespace
71
73{
74 KisApplication *app = qobject_cast<KisApplication *>(KisApplication::instance());
75 if (app) {
76 return app->androidDonations();
77 } else {
78 return nullptr;
79 }
80}
81
83{
84 QAndroidJniObject::callStaticMethod<void>("org/krita/android/MainActivity", "setLoaded", "(Z)V", jboolean(loaded));
85}
86
87void KisAndroidDonations::setLoadingText(const QString &text)
88{
89 QAndroidJniObject textObject = QAndroidJniObject::fromString(text);
90 QAndroidJniObject::callStaticMethod<void>("org/krita/android/MainActivity",
91 "setLoadingText",
92 "(Ljava/lang/String;)V",
93 textObject.object<jstring>());
94}
95
97{
98 QAndroidJniEnvironment env;
99 jbyteArray splashBytes = nullptr;
100 QString splashArtist;
101 if (splash) {
103 splashArtist = source.artistCredit;
104 QFile f(source.resourcePath);
105 if (f.open(QIODevice::ReadOnly)) {
106 QByteArray buf = f.readAll();
107 f.close();
108
109 jsize length = buf.size();
110 if (length > 0) {
111 splashBytes = env->NewByteArray(length);
112 env->SetByteArrayRegion(splashBytes, 0, length, reinterpret_cast<const jbyte *>(buf.constData()));
113 }
114 } else {
115 qWarning("Failed to read splash screen image from '%s': %s",
116 qUtf8Printable(source.resourcePath),
117 qUtf8Printable(f.errorString()));
118 }
119 }
120 QAndroidJniObject splashArtistObject = QAndroidJniObject::fromString(splashArtist);
121 QAndroidJniObject splashVersionObject = QAndroidJniObject::fromString(qApp->applicationVersion());
122 QAndroidJniObject::callStaticMethod<void>("org/krita/android/MainActivity",
123 "showDonationDialog",
124 "(Z[BLjava/lang/String;Ljava/lang/String;)V",
125 jboolean(splash),
126 splashBytes,
127 splashArtistObject.object(),
128 splashVersionObject.object());
129 if (splashBytes) {
130 env->DeleteLocalRef(splashBytes);
131 }
132}
133
135{
136 return m_state == State::Supporter && isProductOwned(QStringLiteral("thankyoukiki"));
137}
138
148
150{
152 QAndroidJniObject currentProducts = QAndroidJniObject::callStaticObjectMethod("org/krita/android/DonationHelper",
153 "getCurrentProducts",
154 "()Ljava/util/List;");
155 jint size = currentProducts.callMethod<jint>("size", "()I");
156 products.reserve(size);
157 for (jint i = 0; i < size; ++i) {
158 QAndroidJniObject javaProduct = currentProducts.callObjectMethod("get", "(I)Ljava/lang/Object;", i);
159
160 products.append(KisSupporterProduct{
161 KisSupporterProductType(javaProduct.callMethod<jint>("getType", "()I")),
162 KisSupporterProductAvailability(javaProduct.callMethod<jint>("getAvailability", "()I")),
163 javaProduct.callObjectMethod("getId", "()Ljava/lang/String;").toString(),
164 javaProduct.callObjectMethod("getTitle", "()Ljava/lang/String;").toString(),
165 javaProduct.callObjectMethod("getDescription", "()Ljava/lang/String;").toString(),
166 getProductIcon(javaProduct),
167 javaProduct.callObjectMethod("getButtonText", "()Ljava/lang/String;").toString(),
168 javaProduct.callObjectMethod("getOfferToken", "()Ljava/lang/String;").toString(),
169 });
170 }
171 return products;
172}
173
174void KisAndroidDonations::startBillingFlowFor(const QString &productId, const QString &offerToken)
175{
176 QAndroidJniObject productIdObject = QAndroidJniObject::fromString(productId);
177 QAndroidJniObject offerTokenObject = QAndroidJniObject::fromString(offerToken);
178 QAndroidJniObject::callStaticMethod<void>("org/krita/android/DonationHelper",
179 "startBillingFlowForProductId",
180 "(Ljava/lang/String;Ljava/lang/String;)V",
181 productIdObject.object<jstring>(),
182 offerTokenObject.object<jstring>());
183}
184
189
191{
192 QAndroidJniObject::callStaticMethod<void>("org/krita/android/MainActivity", "manageSubscriptions", "()V");
193}
194
196{
197 QAndroidJniObject productIdObject = QAndroidJniObject::fromString(productId);
198 QAndroidJniObject::callStaticMethod<void>("org/krita/android/MainActivity",
199 "manageSubscription",
200 "(Ljava/lang/String;)V",
201 productIdObject.object<jstring>());
202}
203
204void KisAndroidDonations::slotUpdateState(int state, long long ownedProductFlags)
205{
206 if (int(m_state) != state || m_ownedProductFlags != ownedProductFlags) {
208 m_ownedProductFlags = ownedProductFlags;
209 Q_EMIT sigStateChanged();
210 }
211}
212
214 : QObject(parent)
215{
216 // The state update can come from a different thread, so we'll use a queued connection.
217 connect(this,
219 this,
221 Qt::QueuedConnection);
222}
223
224bool KisAndroidDonations::isProductOwned(const QString &productId) const
225{
226 QAndroidJniObject productIdObject = QAndroidJniObject::fromString(productId);
227 return QAndroidJniObject::callStaticMethod<jboolean>("org/krita/android/DonationHelper",
228 "isProductOwned",
229 "(Ljava/lang/String;)B");
230}
231
233{
234 QAndroidJniObject::callStaticMethod<void>("org/krita/android/DonationHelper", "syncState", "()V");
235}
236
237extern "C" JNIEXPORT void JNICALL Java_org_krita_android_JNIWrappers_donationStateUpdated(JNIEnv * /*env*/,
238 jobject /*obj*/,
239 jint state,
240 jlong ownedProductFlags)
241{
242 KisApplication *app = qobject_cast<KisApplication *>(KisApplication::instance());
243 if (app) {
244 KisAndroidDonations *androidDonations = app->androidDonations();
245 if (androidDonations) {
246 Q_EMIT androidDonations->sigStateUpdateReceived(state, ownedProductFlags);
247 }
248 }
249}
250
251extern "C" JNIEXPORT void JNICALL Java_org_krita_android_JNIWrappers_showDonationManagementDialog(JNIEnv * /*env*/,
252 jobject /*obj*/)
253{
254 KisApplication *app = qobject_cast<KisApplication *>(KisApplication::instance());
255 if (app) {
256 KisAndroidDonations *androidDonations = app->androidDonations();
257 if (androidDonations) {
258 androidDonations->setShowDonationManagementDialogPending(true);
259 }
260 }
261}
262
263extern "C" JNIEXPORT void JNICALL Java_org_krita_android_JNIWrappers_onSplashDialogDismissed(JNIEnv * /*env*/,
264 jobject /*obj*/)
265{
266 KisApplication *app = qobject_cast<KisApplication *>(KisApplication::instance());
267 if (app) {
268 KisAndroidDonations *androidDonations = app->androidDonations();
269 if (androidDonations) {
270 Q_EMIT androidDonations->sigSplashDialogDismissed();
271 }
272 }
273}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
JNIEXPORT void JNICALL Java_org_krita_android_JNIWrappers_donationStateUpdated(JNIEnv *, jobject, jint state, jlong ownedProductFlags)
JNIEXPORT void JNICALL Java_org_krita_android_JNIWrappers_onSplashDialogDismissed(JNIEnv *, jobject)
JNIEXPORT void JNICALL Java_org_krita_android_JNIWrappers_showDonationManagementDialog(JNIEnv *, jobject)
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
enum KRITAUI_EXPORT KisSupporterProductAvailability
enum KRITAUI_EXPORT KisSupporterProductType
void slotUpdateState(int state, long long ownedProductFlags)
static void setLoaded(bool loaded)
void setShowDonationManagementDialogPending(bool pending)
static void showDonationDialog(bool splash)
static void setLoadingText(const QString &text)
bool shouldShowSupporterBadge() const
KisAndroidDonations(QObject *parent=nullptr)
static KisAndroidDonations * instance()
void sigSplashDialogDismissed()
void sigShowDonationManagementDialogRequested()
void sigStateUpdateReceived(int state, long long ownedProductFlags)
void startBillingFlowFor(const QString &productId, const QString &offerToken)
void slotManageSubscription(const QString &productId)
QVector< KisSupporterProduct > getCurrentProducts() const
bool isProductOwned(const QString &productId) const
Base class for the Krita app.
static Source getImageSource()