History

Merge remote-tracking branch 'upstream/master' into display_name_and_avatar

Gabriel Calero committed 7 years ago

Commit f67d98f2 parents 6c43199 6cb8cf0170 files · +1107 −2796Browse files

Showing the changes to android/apps/interface/src/main/cpp/native.cpp (1 of 170 files). Show all

Unified · Split

android/apps/interface/src/main/cpp/native.cpp+584−0
@@ -0,0 +1,584 @@
1+#include <functional>
2+
3+
4+#include <QtCore/QBuffer>
5+#include <QtCore/QDebug>
6+#include <QtCore/QDir>
7+#include <QtCore/QFile>
8+#include <QtCore/QThread>
9+#include <QtCore/QStringList>
10+#include <QtCore/QStandardPaths>
11+#include <QtCore/QTextStream>
12+
13+#include <QtAndroidExtras/QAndroidJniObject>
14+
15+#include <android/log.h>
16+#include <android/asset_manager.h>
17+#include <android/asset_manager_jni.h>
18+
19+#include <shared/Storage.h>
20+#include <QObject>
21+
22+#include <AddressManager.h>
23+#include "AndroidHelper.h"
24+#include <udt/PacketHeaders.h>
25+#include <SettingHandle.h>
26+
27+#define AUTO_LOGOUT_SETTING_NAME "wallet/autoLogout"
28+#define WALLET_USERNAME_SETTING_NAME "wallet/savedUsername"
29+
30+QAndroidJniObject __interfaceActivity;
31+QAndroidJniObject __loginCompletedListener;
32+QAndroidJniObject __signupCompletedListener;
33+QAndroidJniObject __loadCompleteListener;
34+QAndroidJniObject __usernameChangedListener;
35+void tempMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
36+ if (!message.isEmpty()) {
37+ const char * local=message.toStdString().c_str();
38+ switch (type) {
39+ case QtDebugMsg:
40+ __android_log_write(ANDROID_LOG_DEBUG,"Interface",local);
41+ break;
42+ case QtInfoMsg:
43+ __android_log_write(ANDROID_LOG_INFO,"Interface",local);
44+ break;
45+ case QtWarningMsg:
46+ __android_log_write(ANDROID_LOG_WARN,"Interface",local);
47+ break;
48+ case QtCriticalMsg:
49+ __android_log_write(ANDROID_LOG_ERROR,"Interface",local);
50+ break;
51+ case QtFatalMsg:
52+ default:
53+ __android_log_write(ANDROID_LOG_FATAL,"Interface",local);
54+ abort();
55+ }
56+ }
57+}
58+
59+AAssetManager* g_assetManager = nullptr;
60+
61+void withAssetData(const char* filename, const std::function<void(off64_t, const void*)>& callback) {
62+ auto asset = AAssetManager_open(g_assetManager, filename, AASSET_MODE_BUFFER);
63+ if (!asset) {
64+ throw std::runtime_error("Failed to open file");
65+ }
66+ auto buffer = AAsset_getBuffer(asset);
67+ off64_t size = AAsset_getLength64(asset);
68+ callback(size, buffer);
69+ AAsset_close(asset);
70+}
71+
72+QStringList readAssetLines(const char* filename) {
73+ QStringList result;
74+ withAssetData(filename, [&](off64_t size, const void* data){
75+ QByteArray buffer = QByteArray::fromRawData((const char*)data, size);
76+ {
77+ QTextStream in(&buffer);
78+ while (!in.atEnd()) {
79+ QString line = in.readLine();
80+ result << line;
81+ }
82+ }
83+ });
84+ return result;
85+}
86+
87+void copyAsset(const char* sourceAsset, const QString& destFilename) {
88+ withAssetData(sourceAsset, [&](off64_t size, const void* data){
89+ QFile file(destFilename);
90+ if (!file.open(QFile::ReadWrite | QIODevice::Truncate)) {
91+ throw std::runtime_error("Unable to open output file for writing");
92+ }
93+ if (!file.resize(size)) {
94+ throw std::runtime_error("Unable to resize output file");
95+ }
96+ if (size != 0) {
97+ auto mapped = file.map(0, size);
98+ if (!mapped) {
99+ throw std::runtime_error("Unable to map output file");
100+ }
101+ memcpy(mapped, data, size);
102+ }
103+ file.close();
104+ });
105+}
106+
107+void unpackAndroidAssets() {
108+ const QString DEST_PREFIX = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/";
109+
110+ QStringList filesToCopy = readAssetLines("cache_assets.txt");
111+ QString dateStamp = filesToCopy.takeFirst();
112+ QString dateStampFilename = DEST_PREFIX + dateStamp;
113+ qDebug() << "Checking date stamp" << dateStamp;
114+ if (QFileInfo(dateStampFilename).exists()) {
115+ return;
116+ }
117+
118+ auto rootDir = QDir::root();
119+ for (const auto& fileToCopy : filesToCopy) {
120+ auto destFileName = DEST_PREFIX + fileToCopy;
121+ auto destFolder = QFileInfo(destFileName).absoluteDir();
122+ if (!destFolder.exists()) {
123+ qDebug() << "Creating folder" << destFolder.absolutePath();
124+ if (!rootDir.mkpath(destFolder.absolutePath())) {
125+ throw std::runtime_error("Error creating output path");
126+ }
127+ }
128+ if (QFile::exists(destFileName)) {
129+ qDebug() << "Removing old file" << destFileName;
130+ if (!QFile::remove(destFileName)) {
131+ throw std::runtime_error("Failed to remove existing file");
132+ }
133+ }
134+
135+ qDebug() << "Copying asset " << fileToCopy << "to" << destFileName;
136+ copyAsset(fileToCopy.toStdString().c_str(), destFileName);
137+ }
138+
139+ {
140+ qDebug() << "Writing date stamp" << dateStamp;
141+ QFile file(dateStampFilename);
142+ if (!file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
143+ throw std::runtime_error("Can't write date stamp");
144+ }
145+ QTextStream(&file) << "touch" << endl;
146+ file.close();
147+ }
148+}
149+
150+extern "C" {
151+
152+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject instance, jobject asset_mgr) {
153+ g_assetManager = AAssetManager_fromJava(env, asset_mgr);
154+ qRegisterMetaType<QAndroidJniObject>("QAndroidJniObject");
155+ __interfaceActivity = QAndroidJniObject(instance);
156+ auto oldMessageHandler = qInstallMessageHandler(tempMessageHandler);
157+ unpackAndroidAssets();
158+ qInstallMessageHandler(oldMessageHandler);
159+
160+ JavaVM* jvm;
161+ env->GetJavaVM(&jvm);
162+
163+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested, [jvm](const QString& a, const bool backToScene, QMap<QString, QString> args) {
164+ JNIEnv* myNewEnv;
165+ JavaVMAttachArgs jvmArgs;
166+ jvmArgs.version = JNI_VERSION_1_6; // choose your JNI version
167+ jvmArgs.name = NULL; // you might want to give the java thread a name
168+ jvmArgs.group = NULL; // you might want to assign the java thread to a ThreadGroup
169+
170+ int attachedHere = 0; // know if detaching at the end is necessary
171+ jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
172+ if (JNI_OK != res) {
173+ qDebug() << "[JCRASH] GetEnv env not attached yet, attaching now..";
174+ res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
175+ if (JNI_OK != res) {
176+ qDebug() << "[JCRASH] Failed to AttachCurrentThread, ErrorCode = " << res;
177+ return;
178+ } else {
179+ attachedHere = 1;
180+ }
181+ }
182+
183+ QAndroidJniObject string = QAndroidJniObject::fromString(a);
184+ jboolean jBackToScene = (jboolean) backToScene;
185+ jclass hashMapClass = myNewEnv->FindClass("java/util/HashMap");
186+ jmethodID mapClassConstructor = myNewEnv->GetMethodID(hashMapClass, "<init>", "()V");
187+ jobject hashmap = myNewEnv->NewObject(hashMapClass, mapClassConstructor);
188+ jmethodID mapClassPut = myNewEnv->GetMethodID(hashMapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
189+ QMap<QString, QString>::iterator i;
190+ for (i = args.begin(); i != args.end(); ++i) {
191+ QAndroidJniObject jKey = QAndroidJniObject::fromString(i.key());
192+ QAndroidJniObject jValue = QAndroidJniObject::fromString(i.value());
193+ myNewEnv->CallObjectMethod(hashmap, mapClassPut, jKey.object<jstring>(), jValue.object<jstring>());
194+ }
195+ __interfaceActivity.callMethod<void>("openAndroidActivity", "(Ljava/lang/String;ZLjava/util/HashMap;)V", string.object<jstring>(), jBackToScene, hashmap);
196+ if (attachedHere) {
197+ jvm->DetachCurrentThread();
198+ }
199+ });
200+
201+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::hapticFeedbackRequested, [](int duration) {
202+ jint iDuration = (jint) duration;
203+ __interfaceActivity.callMethod<void>("performHapticFeedback", "(I)V", iDuration);
204+ });
205+}
206+
207+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnDestroy(JNIEnv* env, jobject obj) {
208+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::androidActivityRequested,
209+ nullptr, nullptr);
210+
211+}
212+
213+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGotoUrl(JNIEnv* env, jobject obj, jstring url) {
214+ QAndroidJniObject jniUrl("java/lang/String", "(Ljava/lang/String;)V", url);
215+ DependencyManager::get<AddressManager>()->loadSettings(jniUrl.toString());
216+ AndroidHelper::instance().muteMic();
217+}
218+
219+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeGoToUser(JNIEnv* env, jobject obj, jstring username) {
220+ QAndroidJniObject jniUsername("java/lang/String", "(Ljava/lang/String;)V", username);
221+ DependencyManager::get<AddressManager>()->goToUser(jniUsername.toString(), false);
222+ AndroidHelper::instance().muteMic();
223+}
224+
225+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) {
226+}
227+
228+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnResume(JNIEnv* env, jobject obj) {
229+}
230+
231+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnExitVr(JNIEnv* env, jobject obj) {
232+}
233+
234+// HifiUtils
235+JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_getCurrentAddress(JNIEnv *env, jobject instance) {
236+ QSharedPointer<AddressManager> addressManager = DependencyManager::get<AddressManager>();
237+ if (!addressManager) {
238+ return env->NewString(nullptr, 0);
239+ }
240+
241+ QString str;
242+ if (!addressManager->getPlaceName().isEmpty()) {
243+ str = addressManager->getPlaceName();
244+ } else if (!addressManager->getHost().isEmpty()) {
245+ str = addressManager->getHost();
246+ }
247+
248+ QRegExp pathRegEx("(\\/[^\\/]+)");
249+ if (!addressManager->currentPath().isEmpty() && addressManager->currentPath().contains(pathRegEx) && pathRegEx.matchedLength() > 0) {
250+ str += pathRegEx.cap(0);
251+ }
252+
253+ return env->NewStringUTF(str.toLatin1().data());
254+}
255+
256+JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_HifiUtils_protocolVersionSignature(JNIEnv *env, jobject instance) {
257+ return env->NewStringUTF(protocolVersionsSignatureBase64().toLatin1().data());
258+}
259+
260+JNIEXPORT jstring JNICALL Java_io_highfidelity_hifiinterface_fragment_HomeFragment_nativeGetLastLocation(JNIEnv *env, jobject instance) {
261+ Setting::Handle<QUrl> currentAddressHandle(QStringList() << "AddressManager" << "address", QString());
262+ QUrl lastLocation = currentAddressHandle.get();
263+ return env->NewStringUTF(lastLocation.toString().toLatin1().data());
264+}
265+
266+JNIEXPORT void JNICALL
267+Java_io_highfidelity_hifiinterface_HifiUtils_updateHifiSetting(JNIEnv *env, jobject instance,
268+ jstring group_, jstring key_,
269+ jboolean value_) {
270+ const char *c_group = env->GetStringUTFChars(group_, 0);
271+ const char *c_key = env->GetStringUTFChars(key_, 0);
272+
273+ const QString group = QString::fromUtf8(c_group);
274+ const QString key = QString::fromUtf8(c_key);
275+
276+ env->ReleaseStringUTFChars(group_, c_group);
277+ env->ReleaseStringUTFChars(key_, c_key);
278+
279+ bool value = value_;
280+
281+ Setting::Handle<bool> setting { QStringList() << group << key , !value };
282+ setting.set(value);
283+}
284+
285+JNIEXPORT jboolean JNICALL
286+Java_io_highfidelity_hifiinterface_HifiUtils_getHifiSettingBoolean(JNIEnv *env,
287+ jobject instance,
288+ jstring group_,
289+ jstring key_,
290+ jboolean defaultValue) {
291+ const char *c_group = env->GetStringUTFChars(group_, 0);
292+ const char *c_key = env->GetStringUTFChars(key_, 0);
293+
294+ const QString group = QString::fromUtf8(c_group);
295+ const QString key = QString::fromUtf8(c_key);
296+
297+ env->ReleaseStringUTFChars(group_, c_group);
298+ env->ReleaseStringUTFChars(key_, c_key);
299+
300+ Setting::Handle<bool> setting { QStringList() << group << key , defaultValue};
301+ return setting.get();
302+}
303+
304+JNIEXPORT jboolean JNICALL
305+Java_io_highfidelity_hifiinterface_HifiUtils_isUserLoggedIn(JNIEnv *env, jobject instance) {
306+ return DependencyManager::get<AccountManager>()->isLoggedIn();
307+}
308+
309+JNIEXPORT jboolean JNICALL
310+Java_io_highfidelity_hifiinterface_HifiUtils_isKeepingLoggedIn(JNIEnv *env, jobject instance) {
311+ Setting::Handle<bool> setting(AUTO_LOGOUT_SETTING_NAME, true);
312+ return !setting.get();
313+}
314+
315+JNIEXPORT void JNICALL
316+Java_io_highfidelity_hifiinterface_fragment_LoginFragment_cancelLogin(JNIEnv *env, jobject instance) {
317+
318+ auto accountManager = DependencyManager::get<AccountManager>();
319+
320+ QObject::disconnect(accountManager.data(), &AccountManager::loginComplete, nullptr, nullptr);
321+ QObject::disconnect(accountManager.data(), &AccountManager::loginFailed, nullptr, nullptr);
322+
323+}
324+
325+JNIEXPORT void JNICALL
326+Java_io_highfidelity_hifiinterface_fragment_SignupFragment_cancelLogin(JNIEnv *env,
327+ jobject instance) {
328+
329+ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_cancelLogin(env, instance);
330+}
331+
332+JNIEXPORT void JNICALL
333+Java_io_highfidelity_hifiinterface_fragment_LoginFragment_login(JNIEnv *env, jobject instance,
334+ jstring username_, jstring password_,
335+ jboolean keepLoggedIn) {
336+ const char *c_username = env->GetStringUTFChars(username_, 0);
337+ const char *c_password = env->GetStringUTFChars(password_, 0);
338+ QString username = QString(c_username);
339+ QString password = QString(c_password);
340+ env->ReleaseStringUTFChars(username_, c_username);
341+ env->ReleaseStringUTFChars(password_, c_password);
342+
343+ auto accountManager = DependencyManager::get<AccountManager>();
344+
345+ __loginCompletedListener = QAndroidJniObject(instance);
346+
347+ QObject::connect(accountManager.data(), &AccountManager::loginComplete, [username, keepLoggedIn](const QUrl& authURL) {
348+ jboolean jSuccess = (jboolean) true;
349+ if (__loginCompletedListener.isValid()) {
350+ __loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
351+ }
352+ Setting::Handle<QVariant>(AUTO_LOGOUT_SETTING_NAME).set(!keepLoggedIn);
353+ QString usernameToSave = keepLoggedIn ? username : "";
354+ Setting::Handle<QVariant>(WALLET_USERNAME_SETTING_NAME).set(usernameToSave);
355+ });
356+
357+ QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
358+ jboolean jSuccess = (jboolean) false;
359+ if (__loginCompletedListener.isValid()) {
360+ __loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
361+ }
362+ });
363+
364+ QMetaObject::invokeMethod(accountManager.data(), "requestAccessToken",
365+ Q_ARG(const QString&, username), Q_ARG(const QString&, password));
366+}
367+
368+JNIEXPORT void JNICALL
369+Java_io_highfidelity_hifiinterface_fragment_LoginFragment_retrieveAccessToken(JNIEnv *env,
370+ jobject instance,
371+ jstring authCode_,
372+ jstring clientId_,
373+ jstring clientSecret_,
374+ jstring redirectUri_) {
375+ const char *c_authCode = env->GetStringUTFChars(authCode_, 0);
376+ const char *c_clientId = env->GetStringUTFChars(clientId_, 0);
377+ const char *c_clientSecret = env->GetStringUTFChars(clientSecret_, 0);
378+ const char *c_redirectUri = env->GetStringUTFChars(redirectUri_, 0);
379+
380+ QString authCode = QString(c_authCode);
381+ QString clientId = QString(c_clientId);
382+ QString clientSecret = QString(c_clientSecret);
383+ QString redirectUri = QString(c_redirectUri);
384+
385+ env->ReleaseStringUTFChars(authCode_, c_authCode);
386+ env->ReleaseStringUTFChars(clientId_, c_clientId);
387+ env->ReleaseStringUTFChars(clientSecret_, c_clientSecret);
388+ env->ReleaseStringUTFChars(redirectUri_, c_redirectUri);
389+
390+ auto accountManager = DependencyManager::get<AccountManager>();
391+
392+ __loginCompletedListener = QAndroidJniObject(instance); // TODO: use a different listener?
393+
394+ QObject::connect(accountManager.data(), &AccountManager::loginComplete, [](const QUrl& authURL) {
395+ jboolean jSuccess = (jboolean) true;
396+ if (__loginCompletedListener.isValid()) {
397+ __loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
398+ }
399+ });
400+
401+ QObject::connect(accountManager.data(), &AccountManager::loginFailed, []() {
402+ jboolean jSuccess = (jboolean) false;
403+ if (__loginCompletedListener.isValid()) {
404+ __loginCompletedListener.callMethod<void>("handleLoginCompleted", "(Z)V", jSuccess);
405+ }
406+ });
407+
408+ QMetaObject::invokeMethod(accountManager.data(), "requestAccessTokenWithAuthCode",
409+ Q_ARG(const QString&, authCode), Q_ARG(const QString&, clientId),
410+ Q_ARG(const QString&, clientSecret), Q_ARG(const QString&, redirectUri));
411+
412+}
413+
414+JNIEXPORT void JNICALL
415+Java_io_highfidelity_hifiinterface_fragment_SignupFragment_login(JNIEnv *env,
416+ jobject instance,
417+ jstring username_,
418+ jstring password_,
419+ jboolean keepLoggedIn) {
420+ Java_io_highfidelity_hifiinterface_fragment_LoginFragment_login(env, instance, username_, password_, keepLoggedIn);
421+}
422+
423+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeInitAfterAppLoaded(JNIEnv* env, jobject obj) {
424+ AndroidHelper::instance().moveToThread(qApp->thread());
425+}
426+
427+JNIEXPORT void JNICALL
428+Java_io_highfidelity_hifiinterface_fragment_SignupFragment_signup(JNIEnv *env, jobject instance,
429+ jstring email_, jstring username_,
430+ jstring password_) {
431+
432+ const char *c_email = env->GetStringUTFChars(email_, 0);
433+ const char *c_username = env->GetStringUTFChars(username_, 0);
434+ const char *c_password = env->GetStringUTFChars(password_, 0);
435+ QString email = QString(c_email);
436+ QString username = QString(c_username);
437+ QString password = QString(c_password);
438+ env->ReleaseStringUTFChars(email_, c_email);
439+ env->ReleaseStringUTFChars(username_, c_username);
440+ env->ReleaseStringUTFChars(password_, c_password);
441+
442+ __signupCompletedListener = QAndroidJniObject(instance);
443+
444+ // disconnect any previous callback
445+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, nullptr, nullptr);
446+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, nullptr, nullptr);
447+
448+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, []() {
449+ jboolean jSuccess = (jboolean) true;
450+ if (__signupCompletedListener.isValid()) {
451+ __signupCompletedListener.callMethod<void>("handleSignupCompleted", "()V", jSuccess);
452+ }
453+ });
454+
455+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, [](QString errorString) {
456+ if (__signupCompletedListener.isValid()) {
457+ QAndroidJniObject string = QAndroidJniObject::fromString(errorString);
458+ __signupCompletedListener.callMethod<void>("handleSignupFailed", "(Ljava/lang/String;)V", string.object<jstring>());
459+ }
460+ });
461+
462+ AndroidHelper::instance().signup(email, username, password);
463+}
464+
465+JNIEXPORT void JNICALL
466+Java_io_highfidelity_hifiinterface_fragment_SignupFragment_cancelSignup(JNIEnv *env, jobject instance) {
467+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupCompleted, nullptr, nullptr);
468+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::handleSignupFailed, nullptr, nullptr);
469+
470+ __signupCompletedListener = nullptr;
471+}
472+
473+JNIEXPORT jstring JNICALL
474+Java_io_highfidelity_hifiinterface_fragment_FriendsFragment_nativeGetAccessToken(JNIEnv *env, jobject instance) {
475+ auto accountManager = DependencyManager::get<AccountManager>();
476+ return env->NewStringUTF(accountManager->getAccountInfo().getAccessToken().token.toLatin1().data());
477+}
478+
479+JNIEXPORT void JNICALL
480+Java_io_highfidelity_hifiinterface_SplashActivity_registerLoadCompleteListener(JNIEnv *env,
481+ jobject instance) {
482+
483+ __loadCompleteListener = QAndroidJniObject(instance);
484+
485+ QObject::connect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, []() {
486+
487+ __loadCompleteListener.callMethod<void>("onAppLoadedComplete", "()V");
488+ __interfaceActivity.callMethod<void>("onAppLoadedComplete", "()V");
489+
490+ QObject::disconnect(&AndroidHelper::instance(), &AndroidHelper::qtAppLoadComplete, nullptr,
491+ nullptr);
492+ });
493+
494+}
495+
496+JNIEXPORT jstring JNICALL
497+Java_io_highfidelity_hifiinterface_fragment_ProfileFragment_getDisplayName(JNIEnv *env,
498+ jobject instance) {
499+
500+ QString displayName = AndroidHelper::instance().getDisplayName();
501+ return env->NewStringUTF(displayName.toLatin1().data());
502+}
503+
504+JNIEXPORT void JNICALL
505+Java_io_highfidelity_hifiinterface_fragment_ProfileFragment_setDisplayName(JNIEnv *env,
506+ jobject instance,
507+ jstring name_) {
508+ const char *c_name = env->GetStringUTFChars(name_, 0);
509+ const QString name = QString::fromUtf8(c_name);
510+ env->ReleaseStringUTFChars(name_, c_name);
511+ AndroidHelper::instance().setDisplayName(name);
512+}
513+
514+JNIEXPORT void JNICALL
515+Java_io_highfidelity_hifiinterface_fragment_ProfileFragment_setAvatarUrl(JNIEnv *env,
516+ jobject instance,
517+ jstring url_) {
518+ const char *url = env->GetStringUTFChars(url_, 0);
519+ QString avatarUrl = QString::fromUtf8(url);
520+ AndroidHelper::instance().setMyAvatarUrl(avatarUrl);
521+ env->ReleaseStringUTFChars(url_, url);
522+}
523+
524+JNIEXPORT void JNICALL
525+Java_io_highfidelity_hifiinterface_MainActivity_logout(JNIEnv *env, jobject instance) {
526+ DependencyManager::get<AccountManager>()->logout();
527+}
528+
529+JNIEXPORT jstring JNICALL
530+Java_io_highfidelity_hifiinterface_MainActivity_getUsername(JNIEnv *env,
531+ jobject instance) {
532+ QString username = DependencyManager::get<AccountManager>()->getAccountInfo().getUsername();
533+ return env->NewStringUTF(username.toLatin1().data());
534+}
535+
536+JNIEXPORT void JNICALL
537+Java_io_highfidelity_hifiinterface_MainActivity_setUsernameChangedListener(JNIEnv *env,
538+ jobject instance,
539+ jobject usernameChangedListener) {
540+ __usernameChangedListener = QAndroidJniObject(usernameChangedListener);
541+
542+ if (!__usernameChangedListener.isValid()) {
543+ return;
544+ }
545+
546+ auto accountManager = DependencyManager::get<AccountManager>();
547+
548+ QObject::connect(accountManager.data(), &AccountManager::usernameChanged, [](const QString& username) {
549+ QAndroidJniObject string = QAndroidJniObject::fromString(username);
550+ if (__usernameChangedListener.isValid()) {
551+ __usernameChangedListener.callMethod<void>("handleUsernameChanged", "(Ljava/lang/String;)V", string.object<jstring>());
552+ }
553+ });
554+
555+}
556+
557+JNIEXPORT void JNICALL
558+Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeBeforeEnterBackground(JNIEnv *env, jobject obj) {
559+ AndroidHelper::instance().notifyBeforeEnterBackground();
560+}
561+
562+JNIEXPORT void JNICALL
563+Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterBackground(JNIEnv *env, jobject obj) {
564+ AndroidHelper::instance().notifyEnterBackground();
565+}
566+
567+JNIEXPORT void JNICALL
568+Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeEnterForeground(JNIEnv *env, jobject obj) {
569+ AndroidHelper::instance().notifyEnterForeground();
570+}
571+
572+JNIEXPORT void Java_io_highfidelity_hifiinterface_WebViewActivity_nativeProcessURL(JNIEnv* env, jobject obj, jstring url_str) {
573+ const char *nativeString = env->GetStringUTFChars(url_str, 0);
574+ AndroidHelper::instance().processURL(QString::fromUtf8(nativeString));
575+}
576+
577+JNIEXPORT void JNICALL
578+Java_io_highfidelity_hifiinterface_receiver_HeadsetStateReceiver_notifyHeadsetOn(JNIEnv *env,
579+ jobject instance,
580+ jboolean pluggedIn) {
581+ AndroidHelper::instance().notifyHeadsetOn(pluggedIn);
582+}
583+
584+}