1 /* GCompris - ApplicationInfo.h 2 * 3 * SPDX-FileCopyrightText: 2014-2015 Bruno Coudoin <bruno.coudoin@gcompris.net> 4 * 5 * Authors: 6 * Bruno Coudoin <bruno.coudoin@gcompris.net> 7 * 8 * This file was originally created from Digia example code under BSD license 9 * and heavily modified since then. 10 * 11 * SPDX-License-Identifier: GPL-3.0-or-later 12 */ 13 #ifndef APPLICATIONINFO_H 14 #define APPLICATIONINFO_H 15 16 #include <config.h> 17 #include "ApplicationSettings.h" 18 19 #include <QObject> 20 #include <QLocale> 21 #include <QQmlEngine> 22 #include <QtGlobal> 23 24 class QQuickWindow; 25 26 /** 27 * @class ApplicationInfo 28 * @short A general purpose singleton that exposes miscellaneous native 29 * functions to the QML layer. 30 * @ingroup infrastructure 31 */ 32 class ApplicationInfo : public QObject 33 { 34 Q_OBJECT 35 36 /** 37 * Width of the application viewport. 38 */ 39 Q_PROPERTY(int applicationWidth READ applicationWidth WRITE setApplicationWidth NOTIFY applicationWidthChanged) 40 41 /** 42 * Platform the application is currently running on. 43 */ 44 Q_PROPERTY(Platform platform READ platform CONSTANT) 45 46 /** 47 * Whether the application is currently running on a mobile platform. 48 * 49 * Mobile platforms are Android, Ios (not supported yet), 50 * Blackberry (not supported) 51 */ 52 Q_PROPERTY(bool isMobile READ isMobile CONSTANT) 53 54 /** 55 * Whether the current platform supports fragment shaders. 56 * 57 * This flag is used in some core modules to selectively deactivate 58 * particle effects which cause crashes on some Android devices. 59 * 60 * cf. https://bugreports.qt.io/browse/QTBUG-44194 61 * 62 * For now always set to false, to prevent crashes. 63 */ 64 Q_PROPERTY(bool hasShader READ hasShader CONSTANT) 65 66 /** 67 * Whether currently in portrait mode, on mobile platforms. 68 * 69 * Based on viewport geometry. 70 */ 71 Q_PROPERTY(bool isPortraitMode READ isPortraitMode WRITE setIsPortraitMode NOTIFY portraitModeChanged) 72 73 /** 74 * Ratio factor used for scaling of sizes on high-dpi devices. 75 * 76 * Must be used by activities as a scaling factor to all pixel values. 77 */ 78 Q_PROPERTY(qreal ratio READ ratio NOTIFY ratioChanged) 79 80 /** 81 * Ratio factor used for font scaling. 82 * 83 * On some low-dpi Android devices with high res (e.g. Galaxy Tab 4) the 84 * fonts in Text-like elements appear too small with respect to the other 85 * graphics -- also if we are using font.pointSize. 86 * 87 * For these cases we calculate a fontRatio in ApplicationInfo that takes 88 * dpi information into account, as proposed on 89 * https://doc.qt.io/qt-5/scalability.html#calculating-scaling-ratio 90 * 91 * GCText applies this factor automatically on its new fontSize property. 92 */ 93 Q_PROPERTY(qreal fontRatio READ fontRatio NOTIFY fontRatioChanged) 94 95 /** 96 * Short (2-letter) locale string of the currently active language. 97 */ 98 Q_PROPERTY(QString localeShort READ localeShort CONSTANT) 99 100 /** 101 * GCompris version string (compile time). 102 */ 103 Q_PROPERTY(QString GCVersion READ GCVersion CONSTANT) 104 105 /** 106 * GCompris version code (compile time). 107 */ 108 Q_PROPERTY(int GCVersionCode READ GCVersionCode CONSTANT) 109 110 /** 111 * Qt version string (runtime). 112 */ 113 Q_PROPERTY(QString QTVersion READ QTVersion CONSTANT) 114 115 /** 116 * Audio codec used for voices resources. 117 * 118 * This is determined at compile time (ogg for free platforms, aac on 119 * MacOSX and IOS). 120 */ 121 Q_PROPERTY(QString CompressedAudio READ CompressedAudio CONSTANT) 122 123 /** 124 * Download allowed 125 * 126 * This is determined at compile time. If set to NO GCompris will 127 * never download anything. 128 */ 129 Q_PROPERTY(bool isDownloadAllowed READ isDownloadAllowed CONSTANT) 130 131 /** 132 * Whether the application is currently using OpenGL or not. 133 * 134 * Use to deactivate some effects if OpenGL not used. 135 */ 136 Q_PROPERTY(bool useOpenGL READ useOpenGL WRITE setUseOpenGL NOTIFY useOpenGLChanged) 137 138 /** 139 * Whether Box2D is installed or not. 140 * 141 * Use to disable activities that use Box2D when it's not installed. 142 */ 143 Q_PROPERTY(bool isBox2DInstalled READ isBox2DInstalled NOTIFY isBox2DInstalledChanged) 144 145 public: 146 /** 147 * Known host platforms. 148 */ 149 enum Platform { 150 Linux, /**< Linux (except Android) */ 151 Windows, /**< Windows */ 152 MacOSX, /**< MacOSX */ 153 Android, /**< Android */ 154 Ios, /**< IOS (not supported) */ 155 Blackberry, /**< Blackberry (not supported) */ 156 SailfishOS, /**< SailfishOS */ 157 UbuntuTouchOS /**< UbuntuTouch OS */ 158 }; 159 160 Q_ENUM(Platform) 161 162 /** 163 * Returns an absolute and platform independent path to the passed @p file 164 * 165 * @param file A relative filename. 166 * @returns Absolute path to the file. 167 */ 168 static QString getFilePath(const QString &file); 169 170 /** 171 * Returns the short locale name for the passed @p locale. 172 * 173 * Handles also 'system' (GC_DEFAULT_LOCALE) correctly which resolves to 174 * QLocale::system().name(). 175 * 176 * @param locale A locale string of the form \<language\>_\<country\> 177 * @returns A short locale string of the form \<language\> 178 */ localeShort(const QString & locale)179 static QString localeShort(const QString &locale) 180 { 181 QString _locale = locale; 182 if (_locale == GC_DEFAULT_LOCALE) { 183 _locale = QLocale::system().name(); 184 } 185 if (_locale == "C") { 186 _locale = "en_US"; 187 } 188 // Can't use left(2) because of Asturian where there are 3 chars 189 return _locale.left(_locale.indexOf('_')); 190 } 191 192 /** 193 * Returns a locale string that can be used in voices filenames. 194 * 195 * @param locale A locale string of the form \<language\>_\<country\> 196 * @returns A locale string as used in voices filenames. 197 */ 198 Q_INVOKABLE QString getVoicesLocale(const QString &locale); 199 200 /** 201 * Request GCompris to take the Audio Focus at the system level. 202 * 203 * On systems that support it, it will mute a running audio player. 204 */ 205 Q_INVOKABLE bool requestAudioFocus() const; 206 207 /** 208 * Abandon the Audio Focus. 209 * 210 * On systems that support it, it will let an audio player start again. 211 */ 212 Q_INVOKABLE void abandonAudioFocus() const; 213 214 /** 215 * Compare two strings respecting locale specific sort order. 216 * 217 * @param a First string to compare 218 * @param b Second string to compare 219 * @param locale Locale to respect for comparison in any of the forms 220 * used in GCompris xx[_XX][.codeset]. Defaults to currently 221 * set language from global configuration. 222 * @returns -1, 0 or 1 if a is less than, equal to or greater than b 223 */ 224 Q_INVOKABLE int localeCompare(const QString &a, const QString &b, const QString &locale = "") const; 225 226 /** 227 * Sort a list of strings respecting locale specific sort order. 228 * 229 * This function is supposed to be called from QML/JS. As there are still 230 * problems marshalling QStringList from C++ to QML/JS we use QVariantList 231 * both for argument and return value. 232 * 233 * @param list List of strings to be sorted. 234 * @param locale Locale to respect for sorting in any of the forms 235 * used in GCompris xx[_XX][.codeset]. 236 * @returns List sorted by the sort order of the passed locale. 237 */ 238 Q_INVOKABLE QVariantList localeSort(QVariantList list, const QString &locale = "") const; 239 240 /// @cond INTERNAL_DOCS 241 getInstance()242 static ApplicationInfo *getInstance() 243 { 244 if (!m_instance) { 245 m_instance = new ApplicationInfo(); 246 } 247 return m_instance; 248 } 249 static QObject *applicationInfoProvider(QQmlEngine *engine, 250 QJSEngine *scriptEngine); 251 static void setWindow(QQuickWindow *window); 252 explicit ApplicationInfo(QObject *parent = 0); 253 ~ApplicationInfo(); applicationWidth()254 int applicationWidth() const { return m_applicationWidth; } 255 void setApplicationWidth(const int newWidth); platform()256 Platform platform() const { return m_platform; } isPortraitMode()257 bool isPortraitMode() const { return m_isPortraitMode; } 258 void setIsPortraitMode(const bool newMode); isMobile()259 bool isMobile() const { return m_isMobile; } hasShader()260 bool hasShader() const 261 { 262 #if defined(Q_OS_ANDROID) 263 return false; 264 #else 265 return true; 266 #endif 267 } ratio()268 qreal ratio() const { return m_ratio; } fontRatio()269 qreal fontRatio() const { return m_fontRatio; } localeShort()270 QString localeShort() const 271 { 272 return localeShort(ApplicationSettings::getInstance()->locale()); 273 } GCVersion()274 static QString GCVersion() { return VERSION; } GCVersionCode()275 static int GCVersionCode() { return VERSION_CODE; } QTVersion()276 static QString QTVersion() { return qVersion(); } CompressedAudio()277 static QString CompressedAudio() { return COMPRESSED_AUDIO; } isDownloadAllowed()278 static bool isDownloadAllowed() { return QString(DOWNLOAD_ALLOWED) == "ON"; } useOpenGL()279 bool useOpenGL() const { return m_useOpenGL; } setUseOpenGL(bool useOpenGL)280 void setUseOpenGL(bool useOpenGL) { m_useOpenGL = useOpenGL; } 281 isBox2DInstalled()282 bool isBox2DInstalled() const { return m_isBox2DInstalled; } 283 void setBox2DInstalled(const QQmlEngine &engine); 284 285 /** 286 * Returns the native screen orientation. 287 * 288 * Wraps QScreen::nativeOrientation: The native orientation of the screen 289 * is the orientation where the logo sticker of the device appears the 290 * right way up, or Qt::PrimaryOrientation if the platform does not support 291 * this functionality. 292 * 293 * The native orientation is a property of the hardware, and does not change 294 */ 295 Q_INVOKABLE Qt::ScreenOrientation getNativeOrientation(); 296 297 /** 298 * Change the desired orientation of the application. 299 * 300 * Android specific function, cf. https://developer.android.com/reference/android/app/Activity.html#setRequestedOrientation(int) 301 * 302 * @param orientation Desired orientation of the application. For possible 303 * values cf. https://developer.android.com/reference/android/content/pm/ActivityInfo.html#screenOrientation . 304 * Some useful values: 305 * - -1: SCREEN_ORIENTATION_UNSPECIFIED 306 * - 0: SCREEN_ORIENTATION_LANDSCAPE: forces landscape 307 * - 1: SCREEN_ORIENTATION_PORTRAIT: forces portrait 308 * - 5: SCREEN_ORIENTATION_NOSENSOR: forces native 309 * orientation mode on each device (portrait on 310 * smartphones, landscape on tablet) 311 * - 14: SCREEN_ORIENTATION_LOCKED: lock current orientation 312 */ 313 Q_INVOKABLE void setRequestedOrientation(int orientation); 314 315 /** 316 * Query the desired orientation of the application. 317 * 318 * @sa setRequestedOrientation 319 */ 320 Q_INVOKABLE int getRequestedOrientation(); 321 322 /** 323 * Checks whether a sensor type from the QtSensor module is supported on 324 * the current platform. 325 * 326 * @param sensorType Classname of a sensor from the QtSensor module 327 * to be checked (e.g. "QTiltSensor"). 328 */ 329 Q_INVOKABLE bool sensorIsSupported(const QString &sensorType); 330 331 /** 332 * Toggles activation of screensaver on android 333 * 334 * @param value Whether screensaver should be disabled (true) or 335 * enabled (false). 336 */ 337 Q_INVOKABLE void setKeepScreenOn(bool value); 338 339 /** 340 * Ask for permissions for reading/writing in storage for android. 341 * Do nothing for other platforms. 342 * 343 * https://developer.android.com/training/permissions/requesting 344 * https://doc.qt.io/qt-5/qtandroid.html#requestPermissions 345 * Needed for android above 6.0 346 */ 347 bool checkPermissions() const; 348 349 /// @endcond 350 351 public slots: 352 /** 353 * Returns the resource root-paths used for GCompris resources. 354 * First look in a local folder if exists, else will look into the rcc files. 355 */ 356 QStringList getResourceDataPaths(); 357 358 /** 359 * Returns an absolute path to a language specific sound/voices file. If 360 * the file is already absolute only the token replacement is applied. 361 * 362 * @param file A templated relative path to a language specific file. Any 363 * occurrence of the '$LOCALE' placeholder will be replaced by 364 * the currently active locale string. 365 * Any occurrence of '$CA' placeholder will be replaced by 366 * the current compressed audio format ('ogg' or 'aac). 367 * Example: 'voices-$CA/$LOCALE/misc/click_on_letter.$CA' 368 * @returns An absolute path to the corresponding resource file. 369 */ 370 Q_INVOKABLE QString getAudioFilePath(const QString &file); 371 372 /** 373 * Returns an absolute path to a language specific sound/voices file. If 374 * the file is already absolute only the token replacement is applied. 375 * 376 * @param file A templated relative path to a language specific file. Any 377 * occurrence of the '$LOCALE' placeholder will be replaced by 378 * the currently active locale string. 379 * Any occurrence of '$CA' placeholder will be replaced by 380 * the current compressed audio format ('ogg' or 'aac). 381 * Example: 'voices-$CA/$LOCALE/misc/click_on_letter.$CA' 382 * @param localeName the locale for which to get this audio file 383 * @returns An absolute path to the corresponding resource file. 384 */ 385 Q_INVOKABLE QString getAudioFilePathForLocale(const QString &file, 386 const QString &localeName); 387 388 /** 389 * Returns an absolute path to a language specific resource file. 390 * 391 * Generalization of getAudioFilePath(). 392 * @sa getAudioFilePath 393 */ 394 Q_INVOKABLE QString getLocaleFilePath(const QString &file); 395 396 /** 397 * @returns A list of systems-fonts that should be excluded from font 398 * selection. 399 */ 400 Q_INVOKABLE QStringList getSystemExcludedFonts(); 401 402 /** 403 * @returns A list of fonts contained in the fonts resources. 404 */ 405 Q_INVOKABLE QStringList getFontsFromRcc(); 406 /** 407 * @returns A list of background music contained in the background music resources. 408 */ 409 Q_INVOKABLE QStringList getBackgroundMusicFromRcc(); 410 /** 411 * Stores a screenshot in the passed @p file. 412 * 413 * @param file Absolute destination filename. 414 */ 415 Q_INVOKABLE void screenshot(const QString &file); 416 417 void notifyPortraitMode(); 418 Q_INVOKABLE void notifyFullscreenChanged(); 419 420 protected: getSizeWithRatio(const qreal height)421 qreal getSizeWithRatio(const qreal height) { return ratio() * height; } 422 423 signals: 424 void applicationWidthChanged(); 425 void portraitModeChanged(); 426 void ratioChanged(); 427 void fontRatioChanged(); 428 void applicationSettingsChanged(); 429 void fullscreenChanged(); 430 void useOpenGLChanged(); 431 void isBox2DInstalledChanged(); 432 433 private: 434 static ApplicationInfo *m_instance; 435 int m_applicationWidth; 436 Platform m_platform; 437 bool m_isPortraitMode; 438 bool m_isMobile; 439 bool m_useOpenGL; 440 bool m_isBox2DInstalled; 441 qreal m_ratio; 442 qreal m_fontRatio; 443 444 // Symbols fonts that user can't see 445 QStringList m_excludedFonts; 446 QStringList m_fontsFromRcc; 447 QStringList m_backgroundMusicFromRcc; 448 449 static QQuickWindow *m_window; 450 }; 451 452 #endif // APPLICATIONINFO_H 453