/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. * This project including source code and documentation is protected by * copyright law, and remains the property of nymea GmbH. All rights, including * reproduction, publication, editing and translation, are reserved. The use of * this project is subject to the terms of a license agreement to be concluded * with nymea GmbH in accordance with the terms of use of nymea GmbH, available * under https://nymea.io/license * * GNU General Public License Usage * Alternatively, this project may be redistributed and/or modified under the * terms of the GNU General Public License as published by the Free Software * Foundation, GNU version 3. This project is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with * this project. If not, see . * * For any further details and any questions please contact us under * contact@nymea.io or see our FAQ/Licensing Information on * https://nymea.io/license/faq * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "platformhelperandroid.h" #include #include #include #include // WindowManager.LayoutParams #define FLAG_TRANSLUCENT_STATUS 0x04000000 #define FLAG_TRANSLUCENT_NAVIGATION 0x08000000 #define FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 0x80000000 // View #define SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 0x00002000 #define SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR 0x00000010 static PlatformHelperAndroid *m_instance = nullptr; static JNINativeMethod methods[] = { { "darkModeEnabledChangedJNI", "()V", (void *)PlatformHelperAndroid::darkModeEnabledChangedJNI }, }; JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } jclass javaClass = env->FindClass("io/guh/nymeaapp/NymeaAppActivity"); if (!javaClass) return JNI_ERR; if (env->RegisterNatives(javaClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) { return JNI_ERR; } return JNI_VERSION_1_6; } static QAndroidJniObject getAndroidWindow() { QAndroidJniObject window = QtAndroid::androidActivity().callObjectMethod("getWindow", "()Landroid/view/Window;"); return window; } PlatformHelperAndroid::PlatformHelperAndroid(QObject *parent) : PlatformHelper(parent) { m_instance = this; } void PlatformHelperAndroid::requestPermissions() { // Not using any fancy permissions in android yet... } void PlatformHelperAndroid::hideSplashScreen() { // Android's splash will flicker when fading out twice static bool alreadyHiding = false; if (!alreadyHiding) { QtAndroid::hideSplashScreen(250); alreadyHiding = true; } } bool PlatformHelperAndroid::hasPermissions() const { // Not using any fancy permissions in android yet... return true; } QString PlatformHelperAndroid::machineHostname() const { // QSysInfo::machineHostname always gives "localhost" on android... best we can do here is: return deviceManufacturer() + " " + deviceModel(); } QString PlatformHelperAndroid::deviceSerial() const { QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); return activity.callObjectMethod("deviceSerial").toString(); } QString PlatformHelperAndroid::device() const { return QAndroidJniObject::callStaticObjectMethod("io/guh/nymeaapp/NymeaAppActivity","device").toString(); } QString PlatformHelperAndroid::deviceModel() const { return QAndroidJniObject::callStaticObjectMethod("io/guh/nymeaapp/NymeaAppActivity","deviceModel").toString(); } QString PlatformHelperAndroid::deviceManufacturer() const { return QAndroidJniObject::callStaticObjectMethod("io/guh/nymeaapp/NymeaAppActivity","deviceManufacturer").toString(); } void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType) { int duration; switch (feedbackType) { case HapticsFeedbackSelection: duration = 10; break; case HapticsFeedbackImpact: duration = 30; break; case HapticsFeedbackNotification: duration = 500; break; } QtAndroid::androidActivity().callMethod("vibrate","(I)V", duration); } //void PlatformHelperAndroid::syncThings() //{ // QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(), // "io/guh/nymeaapp/NymeaAppService"); // QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod( // "startService", // "(Landroid/content/Intent;)Landroid/content/ComponentName;", // serviceIntent.handle().object()); //// QtAndroid::androidService() //// QAndroidIntent serviceIntent(QtAndroid::androidActivity().object(), //// "io/guh/nymeaapp/NymeaAppControlService"); //// serviceIntent.putExtra("name", QByteArray("foobar")); //// m_serviceConnection->handle().callMethod("syncThings", "(Ljava/lang/String;)V", "bla"); //// QAndroidJniObject result = QtAndroid::androidActivity().callObjectMethod( //// "syncThings", //// "(Landroid/content/Intent;)Landroid/content/ComponentName;", //// m_serviceConnection->handle().object()); //} void PlatformHelperAndroid::setTopPanelColor(const QColor &color) { PlatformHelper::setTopPanelColor(color); if (QtAndroid::androidSdkVersion() < 21) return; QtAndroid::runOnAndroidThread([=]() { QAndroidJniObject window = getAndroidWindow(); window.callMethod("addFlags", "(I)V", FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_STATUS); window.callMethod("setStatusBarColor", "(I)V", color.rgba()); }); if (((color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000) > 123) { setTopPanelTheme(Light); } else { setTopPanelTheme(Dark); } } void PlatformHelperAndroid::setBottomPanelColor(const QColor &color) { PlatformHelper::setBottomPanelColor(color); if (QtAndroid::androidSdkVersion() < 21) return; QtAndroid::runOnAndroidThread([=]() { QAndroidJniObject window = getAndroidWindow(); window.callMethod("clearFlags", "(I)V", FLAG_TRANSLUCENT_NAVIGATION); window.callMethod("setNavigationBarColor", "(I)V", color.rgba()); if (((color.red() * 299 + color.green() * 587 + color.blue() * 114) / 1000) > 123) { setBottomPanelTheme(Light); } else { setBottomPanelTheme(Dark); } }); } void PlatformHelperAndroid::setTopPanelTheme(PlatformHelperAndroid::Theme theme) { if (QtAndroid::androidSdkVersion() < 23) return; QtAndroid::runOnAndroidThread([=]() { QAndroidJniObject window = getAndroidWindow(); QAndroidJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;"); int visibility = view.callMethod("getSystemUiVisibility", "()I"); if (theme == Theme::Light) visibility |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; else visibility &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; view.callMethod("setSystemUiVisibility", "(I)V", visibility); }); } void PlatformHelperAndroid::setBottomPanelTheme(Theme theme) { if (QtAndroid::androidSdkVersion() < 23) return; QtAndroid::runOnAndroidThread([=]() { QAndroidJniObject window = getAndroidWindow(); QAndroidJniObject view = window.callObjectMethod("getDecorView", "()Landroid/view/View;"); int visibility = view.callMethod("getSystemUiVisibility", "()I"); if (theme == Theme::Light) visibility |= SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; else visibility &= ~SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; view.callMethod("setSystemUiVisibility", "(I)V", visibility); }); } bool PlatformHelperAndroid::darkModeEnabled() const { return QtAndroid::androidActivity().callMethod("darkModeEnabled"); } void PlatformHelperAndroid::shareFile(const QString &fileName) { QtAndroid::androidActivity().callMethod("shareFile", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(fileName).object() ); } void PlatformHelperAndroid::permissionRequestFinished(const QtAndroid::PermissionResultMap &result) { foreach (const QString &key, result.keys()) { qDebug() << "Permission result:" << key << static_cast(result.value(key)); } emit m_instance->permissionsRequestFinished(); } void PlatformHelperAndroid::darkModeEnabledChangedJNI() { if (m_instance) { emit m_instance->darkModeEnabledChanged(); } }