1 /*
2 Copyright (C) 2014 Aseman
3 http://aseman.co
4
5 This project is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This project is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #define LINUX_DEFAULT_DPI 96
20 #define WINDOWS_DEFAULT_DPI 96
21 #define UTOUCH_DEFAULT_DPI 76
22
23 #include "asemandevices.h"
24 #include "asemanapplication.h"
25
26 #ifdef Q_OS_ANDROID
27 #include "asemanjavalayer.h"
28 #endif
29
30 #include <QTimerEvent>
31 #include <QGuiApplication>
32 #include <QMimeType>
33 #include <QMimeDatabase>
34 #include <QUrl>
35 #include <QDesktopServices>
36 #include <QDir>
37 #include <QFileInfo>
38 #include <QFile>
39 #include <QClipboard>
40 #include <QtCore/qmath.h>
41 #include <QScreen>
42 #include <QDateTime>
43 #include <QDebug>
44 #include <QMimeData>
45
46 #ifdef ASEMAN_MULTIMEDIA
47 #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
48 #include <QCameraInfo>
49 #endif
50 #endif
51
52 #ifdef Q_OS_WIN
53 #include <QSysInfo>
54 #endif
55
56 class AsemanDevicesPrivate
57 {
58 public:
59 int hide_keyboard_timer;
60 bool keyboard_stt;
61
62 QMimeDatabase mime_db;
63
64 #ifdef Q_OS_ANDROID
65 AsemanJavaLayer *java_layer;
66 #endif
67 };
68
AsemanDevices(QObject * parent)69 AsemanDevices::AsemanDevices(QObject *parent) :
70 QObject(parent)
71 {
72 p = new AsemanDevicesPrivate;
73 p->hide_keyboard_timer = 0;
74 p->keyboard_stt = false;
75
76 #ifdef Q_OS_ANDROID
77 p->java_layer = AsemanJavaLayer::instance();
78
79 connect( p->java_layer, SIGNAL(incomingShare(QString,QString)), SLOT(incoming_share(QString,QString)), Qt::QueuedConnection );
80 connect( p->java_layer, SIGNAL(incomingImage(QString)) , SLOT(incoming_image(QString)) , Qt::QueuedConnection );
81 connect( p->java_layer, SIGNAL(selectImageResult(QString)) , SLOT(select_image_result(QString)) , Qt::QueuedConnection );
82 connect( p->java_layer, SIGNAL(activityPaused()) , SLOT(activity_paused()) , Qt::QueuedConnection );
83 connect( p->java_layer, SIGNAL(activityResumed()) , SLOT(activity_resumed()) , Qt::QueuedConnection );
84 #endif
85
86 connect( QGuiApplication::inputMethod(), SIGNAL(visibleChanged()), SLOT(keyboard_changed()) );
87 connect( static_cast<QGuiApplication*>(QCoreApplication::instance())->clipboard(), SIGNAL(dataChanged()), SIGNAL(clipboardChanged()) );
88
89 QScreen *scr = screen();
90 if( scr )
91 connect( scr, SIGNAL(geometryChanged(QRect)), SIGNAL(geometryChanged()) );
92 }
93
isMobile() const94 bool AsemanDevices::isMobile() const
95 {
96 return isTouchDevice() && !isTablet();
97 }
98
isTablet() const99 bool AsemanDevices::isTablet() const
100 {
101 #ifdef Q_OS_ANDROID
102 return isTouchDevice() && p->java_layer->isTablet();
103 #else
104 return isTouchDevice() && lcdPhysicalSize() >= 6;
105 #endif
106 }
107
isLargeTablet() const108 bool AsemanDevices::isLargeTablet() const
109 {
110 #ifdef Q_OS_ANDROID
111 return isTablet() && p->java_layer->getSizeName() == 3;
112 #else
113 return isTouchDevice() && lcdPhysicalSize() >= 9;
114 #endif
115 }
116
isTouchDevice()117 bool AsemanDevices::isTouchDevice()
118 {
119 return isAndroid() || isIOS() || isWindowsPhone() || isUbuntuTouch();
120 }
121
isDesktop()122 bool AsemanDevices::isDesktop()
123 {
124 return !isTouchDevice();
125 }
126
isMacX()127 bool AsemanDevices::isMacX()
128 {
129 #ifdef Q_OS_MAC
130 return true;
131 #else
132 return false;
133 #endif
134 }
135
isWindows()136 bool AsemanDevices::isWindows()
137 {
138 #ifdef Q_OS_WIN
139 return true;
140 #else
141 return false;
142 #endif
143 }
144
isLinux()145 bool AsemanDevices::isLinux()
146 {
147 #if defined(Q_OS_LINUX) || defined(Q_OS_OPENBSD)
148 return true;
149 #else
150 return false;
151 #endif
152 }
153
isAndroid()154 bool AsemanDevices::isAndroid()
155 {
156 #ifdef Q_OS_ANDROID
157 return true;
158 #else
159 return false;
160 #endif
161 }
162
isIOS()163 bool AsemanDevices::isIOS()
164 {
165 #ifdef Q_OS_IOS
166 return true;
167 #else
168 return false;
169 #endif
170 }
171
isUbuntuTouch()172 bool AsemanDevices::isUbuntuTouch()
173 {
174 #ifdef Q_OS_UBUNTUTOUCH
175 return true;
176 #else
177 return false;
178 #endif
179 }
180
isWindowsPhone()181 bool AsemanDevices::isWindowsPhone()
182 {
183 #ifdef Q_OS_WINPHONE
184 return true;
185 #else
186 return false;
187 #endif
188 }
189
isWindows8()190 bool AsemanDevices::isWindows8()
191 {
192 #ifdef Q_OS_WIN
193 return QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS8 ||
194 QSysInfo::windowsVersion() == QSysInfo::WV_WINDOWS8_1;
195 #else
196 return false;
197 #endif
198 }
199
screen() const200 QScreen *AsemanDevices::screen() const
201 {
202 const QList<QScreen*> & screens = QGuiApplication::screens();
203 if( screens.isEmpty() )
204 return 0;
205
206 return screens.first();
207 }
208
screenObj() const209 QObject *AsemanDevices::screenObj() const
210 {
211 return screen();
212 }
213
lcdPhysicalSize() const214 qreal AsemanDevices::lcdPhysicalSize() const
215 {
216 qreal w = lcdPhysicalWidth();
217 qreal h = lcdPhysicalHeight();
218
219 return qSqrt( h*h + w*w );
220 }
221
lcdPhysicalWidth() const222 qreal AsemanDevices::lcdPhysicalWidth() const
223 {
224 if( QGuiApplication::screens().isEmpty() )
225 return 0;
226
227 return (qreal)screenSize().width()/lcdDpiX();
228 }
229
lcdPhysicalHeight() const230 qreal AsemanDevices::lcdPhysicalHeight() const
231 {
232 if( QGuiApplication::screens().isEmpty() )
233 return 0;
234
235 return (qreal)screenSize().height()/lcdDpiY();
236 }
237
lcdDpiX() const238 qreal AsemanDevices::lcdDpiX() const
239 {
240 #ifdef Q_OS_ANDROID
241 return p->java_layer->densityDpi();
242 #else
243 if( QGuiApplication::screens().isEmpty() )
244 return 0;
245
246 QScreen *scr = QGuiApplication::screens().first();
247 return scr->physicalDotsPerInchX();
248 #endif
249 }
250
lcdDpiY() const251 qreal AsemanDevices::lcdDpiY() const
252 {
253 #ifdef Q_OS_ANDROID
254 return p->java_layer->densityDpi();
255 #else
256 if( QGuiApplication::screens().isEmpty() )
257 return 0;
258
259 QScreen *scr = QGuiApplication::screens().first();
260 return scr->physicalDotsPerInchY();
261 #endif
262 }
263
screenSize() const264 QSize AsemanDevices::screenSize() const
265 {
266 #ifdef Q_OS_ANDROID
267 return QSize(p->java_layer->screenSizeWidth(),
268 p->java_layer->screenSizeHeight());
269 #else
270 if( QGuiApplication::screens().isEmpty() )
271 return QSize();
272
273 QScreen *scr = QGuiApplication::screens().first();
274 return scr->size();
275 #endif
276 }
277
keyboardHeight() const278 qreal AsemanDevices::keyboardHeight() const
279 {
280 #ifdef Q_OS_UBUNTUTOUCH
281 return screenSize().height()*0.5;
282 #else
283 const QSize & scr_size = screenSize();
284 bool portrait = scr_size.width()<scr_size.height();
285 if( portrait )
286 {
287 if( isMobile() )
288 return screenSize().height()*0.6;
289 else
290 return screenSize().height()*0.4;
291 }
292 else
293 {
294 if( isMobile() )
295 return screenSize().height()*0.7;
296 else
297 return screenSize().height()*0.5;
298 }
299 #endif
300 }
301
deviceName() const302 QString AsemanDevices::deviceName() const
303 {
304 if(isDesktop())
305 #ifdef Q_OS_WIN
306 return QSysInfo::prettyProductName() + " " + QSysInfo::currentCpuArchitecture();
307 #else
308 return "desktop";
309 #endif
310 #ifdef Q_OS_ANDROID
311 else
312 return p->java_layer->deviceName();
313 #else
314 else
315 return "mobile";
316 #endif
317 }
318
transparentStatusBar() const319 bool AsemanDevices::transparentStatusBar() const
320 {
321 #ifdef Q_OS_ANDROID
322 return p->java_layer->transparentStatusBar();
323 #else
324 return false;
325 #endif
326 }
327
transparentNavigationBar() const328 bool AsemanDevices::transparentNavigationBar() const
329 {
330 #ifdef Q_OS_ANDROID
331 return p->java_layer->transparentNavigationBar();
332 #else
333 return false;
334 #endif
335 }
336
standardTitleBarHeight() const337 qreal AsemanDevices::standardTitleBarHeight() const
338 {
339 static qreal res = 0;
340 if(res)
341 return res;
342
343 if(isDesktop() || lcdPhysicalSize()<5)
344 res = 50*density()*1.2;
345 else
346 res = 50*density();
347
348 return res;
349 }
350
densityDpi() const351 int AsemanDevices::densityDpi() const
352 {
353 #ifdef Q_OS_ANDROID
354 return p->java_layer->densityDpi();
355 #else
356 return lcdDpiX();
357 #endif
358 }
359
density() const360 qreal AsemanDevices::density() const
361 {
362 #ifdef Q_OS_ANDROID
363 qreal ratio = isTablet()? 1.28 : 1;
364 // if( isLargeTablet() )
365 // ratio = 1.6;
366
367 return p->java_layer->density()*ratio;
368 #else
369 #ifdef Q_OS_IOS
370 qreal ratio = isTablet()? 1.28 : 1;
371 return ratio*densityDpi()/180.0;
372 #else
373 #if defined(Q_OS_LINUX) || defined(Q_OS_OPENBSD)
374 #ifdef Q_OS_UBUNTUTOUCH
375 return screen()->logicalDotsPerInch()/UTOUCH_DEFAULT_DPI;
376 #else
377 return screen()->logicalDotsPerInch()/LINUX_DEFAULT_DPI;
378 #endif
379 #else
380 #ifdef Q_OS_WIN32
381 return 0.95*screen()->logicalDotsPerInch()/WINDOWS_DEFAULT_DPI;
382 #else
383 return 1;
384 #endif
385 #endif
386 #endif
387 #endif
388 }
389
fontDensity() const390 qreal AsemanDevices::fontDensity() const
391 {
392 #ifdef Q_OS_ANDROID
393 qreal ratio = isMobile()? (1.28)*1.25 : (1.28)*1.35;
394 return p->java_layer->density()*ratio;
395 #else
396 #ifdef Q_OS_IOS
397 return 1.4;
398 #else
399 #if defined(Q_OS_LINUX) || defined(Q_OS_OPENBSD)
400 #ifdef Q_OS_UBUNTUTOUCH
401 qreal ratio = 1.3;
402 return ratio*density();
403 #else
404 qreal ratio = 1.3;
405 return ratio*density();
406 #endif
407 #else
408 #ifdef Q_OS_WIN32
409 qreal ratio = 1.4;
410 return ratio*density();
411 #else
412 qreal ratio = 1.3;
413 return ratio*density();
414 #endif
415 #endif
416 #endif
417 #endif
418 }
419
cameraIsAvailable() const420 bool AsemanDevices::cameraIsAvailable() const
421 {
422 #ifdef ASEMAN_MULTIMEDIA
423 #if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
424 return QCameraInfo::availableCameras().count();
425 #else
426 return false;
427 #endif
428 #else
429 return false;
430 #endif
431 }
432
localFilesPrePath()433 QString AsemanDevices::localFilesPrePath()
434 {
435 #ifdef Q_OS_WIN
436 return "file:///";
437 #else
438 return "file://";
439 #endif
440 }
441
clipboard() const442 QString AsemanDevices::clipboard() const
443 {
444 return QGuiApplication::clipboard()->text();
445 }
446
keyboard() const447 bool AsemanDevices::keyboard() const
448 {
449 return p->keyboard_stt;
450 }
451
clipboardUrl() const452 QList<QUrl> AsemanDevices::clipboardUrl() const
453 {
454 return QGuiApplication::clipboard()->mimeData()->urls();
455 }
456
setClipboardUrl(const QList<QUrl> & urls)457 void AsemanDevices::setClipboardUrl(const QList<QUrl> &urls)
458 {
459 QString data = "copy";
460
461 foreach( const QUrl &url, urls )
462 data += "\nfile://" + url.toLocalFile();
463
464 QMimeData *mime = new QMimeData();
465 mime->setUrls(urls);
466 mime->setData( "x-special/gnome-copied-files", data.toUtf8() );
467
468 QGuiApplication::clipboard()->setMimeData(mime);
469 }
470
cameraLocation()471 QString AsemanDevices::cameraLocation()
472 {
473 return AsemanApplication::cameraPath();
474 }
475
picturesLocation()476 QString AsemanDevices::picturesLocation()
477 {
478 QStringList probs;
479 probs = QStandardPaths::standardLocations( QStandardPaths::PicturesLocation );
480
481 #ifdef Q_OS_ANDROID
482 probs << "/sdcard/Pictures";
483 #else
484 probs << QDir::homePath() + "/Pictures";
485 #endif
486
487 foreach( const QString & prob, probs )
488 if( QFile::exists(prob) )
489 return prob;
490
491 return probs.last();
492 }
493
musicsLocation()494 QString AsemanDevices::musicsLocation()
495 {
496 QStringList probs;
497 probs = QStandardPaths::standardLocations( QStandardPaths::MusicLocation );
498
499 #ifdef Q_OS_ANDROID
500 probs << "/sdcard/Music";
501 #else
502 probs << QDir::homePath() + "/Music";
503 #endif
504
505 foreach( const QString & prob, probs )
506 if( QFile::exists(prob) )
507 return prob;
508
509 return probs.last();
510 }
511
documentsLocation()512 QString AsemanDevices::documentsLocation()
513 {
514 QStringList probs;
515 probs = QStandardPaths::standardLocations( QStandardPaths::DocumentsLocation );
516
517 #ifdef Q_OS_ANDROID
518 probs << "/sdcard/documents";
519 probs << "/sdcard/Documents";
520 #else
521 probs << QDir::homePath() + "/Documents";
522 #endif
523
524 foreach( const QString & prob, probs )
525 if( QFile::exists(prob) )
526 return prob;
527
528 return probs.last();
529 }
530
downloadsLocation()531 QString AsemanDevices::downloadsLocation()
532 {
533 QStringList probs;
534 probs = QStandardPaths::standardLocations( QStandardPaths::DownloadLocation );
535
536 #ifdef Q_OS_ANDROID
537 probs << "/sdcard/downloads";
538 probs << "/sdcard/Downloads";
539 #else
540 probs << QDir::homePath() + "/Downloads";
541 #endif
542
543 foreach( const QString & prob, probs )
544 if( QFile::exists(prob) )
545 return prob;
546
547 return probs.last();
548 }
549
resourcePath()550 QString AsemanDevices::resourcePath()
551 {
552 #ifdef Q_OS_ANDROID
553 return "assets:";
554 #else
555 #ifndef Q_OS_MAC
556 QString result = QCoreApplication::applicationDirPath() + "/../share/" + QCoreApplication::applicationName().toLower();
557 QFileInfo file(result);
558 if(file.exists() && file.isDir())
559 return file.filePath();
560 else
561 return QCoreApplication::applicationDirPath() + "/";
562 #else
563 return QCoreApplication::applicationDirPath() + "/../Resources/";
564 #endif
565 #endif
566 }
567
resourcePathQml()568 QString AsemanDevices::resourcePathQml()
569 {
570 #ifdef Q_OS_ANDROID
571 return resourcePath();
572 #else
573 return localFilesPrePath() + resourcePath();
574 #endif
575 }
576
libsPath()577 QString AsemanDevices::libsPath()
578 {
579 #ifndef Q_OS_MAC
580 QString result = QCoreApplication::applicationDirPath() + "/../lib/" + QCoreApplication::applicationName().toLower();
581 QFileInfo file(result);
582 if(file.exists() && file.isDir())
583 return file.filePath();
584 else
585 return QCoreApplication::applicationDirPath() + "/";
586 #else
587 return QCoreApplication::applicationDirPath() + "/../Resources/";
588 #endif
589 }
590
hideKeyboard()591 void AsemanDevices::hideKeyboard()
592 {
593 #ifndef DESKTOP_DEVICE
594 if( p->hide_keyboard_timer )
595 killTimer(p->hide_keyboard_timer);
596
597 p->hide_keyboard_timer = startTimer(250);
598 #endif
599 }
600
showKeyboard()601 void AsemanDevices::showKeyboard()
602 {
603 #ifndef DESKTOP_DEVICE
604 if( p->hide_keyboard_timer )
605 {
606 killTimer(p->hide_keyboard_timer);
607 p->hide_keyboard_timer = 0;
608 }
609
610 QGuiApplication::inputMethod()->show();
611 p->keyboard_stt = true;
612
613 emit keyboardChanged();
614 #endif
615 }
616
share(const QString & subject,const QString & message)617 void AsemanDevices::share(const QString &subject, const QString &message)
618 {
619 #ifdef Q_OS_ANDROID
620 p->java_layer->sharePaper( subject, message );
621 #else
622 QString adrs = QString("mailto:%1?subject=%2&body=%3").arg(QString(),subject,message);
623 QDesktopServices::openUrl( adrs );
624 #endif
625 }
626
openFile(const QString & address)627 void AsemanDevices::openFile(const QString &address)
628 {
629 #ifdef Q_OS_ANDROID
630 const QMimeType & t = p->mime_db.mimeTypeForFile(address);
631 p->java_layer->openFile( address, t.name() );
632 #else
633 QDesktopServices::openUrl( QUrl(address) );
634 #endif
635 }
636
shareFile(const QString & address)637 void AsemanDevices::shareFile(const QString &address)
638 {
639 #ifdef Q_OS_ANDROID
640 const QMimeType & t = p->mime_db.mimeTypeForFile(address);
641 p->java_layer->shareFile( address, t.name() );
642 #else
643 QDesktopServices::openUrl( QUrl(address) );
644 #endif
645 }
646
setClipboard(const QString & text)647 void AsemanDevices::setClipboard(const QString &text)
648 {
649 QGuiApplication::clipboard()->setText( text );
650 }
651
startCameraPicture()652 bool AsemanDevices::startCameraPicture()
653 {
654 #ifdef Q_OS_ANDROID
655 return p->java_layer->startCamera( cameraLocation() + "/aseman_" + QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch()) + ".jpg" );
656 #else
657 return false;
658 #endif
659 }
660
getOpenPictures()661 bool AsemanDevices::getOpenPictures()
662 {
663 #ifdef Q_OS_ANDROID
664 return p->java_layer->getOpenPictures();
665 #else
666 return false;
667 #endif
668 }
669
incoming_share(const QString & title,const QString & msg)670 void AsemanDevices::incoming_share(const QString &title, const QString &msg)
671 {
672 emit incomingShare(title,msg);
673 }
674
incoming_image(const QString & path)675 void AsemanDevices::incoming_image(const QString &path)
676 {
677 emit incomingImage(path);
678 }
679
select_image_result(const QString & path)680 void AsemanDevices::select_image_result(const QString &path)
681 {
682 emit selectImageResult(path);
683 }
684
activity_paused()685 void AsemanDevices::activity_paused()
686 {
687 emit activityPaused();
688 }
689
activity_resumed()690 void AsemanDevices::activity_resumed()
691 {
692 emit activityResumed();
693 }
694
keyboard_changed()695 void AsemanDevices::keyboard_changed()
696 {
697 emit keyboardChanged();
698 }
699
timerEvent(QTimerEvent * e)700 void AsemanDevices::timerEvent(QTimerEvent *e)
701 {
702 if( e->timerId() == p->hide_keyboard_timer )
703 {
704 killTimer(p->hide_keyboard_timer);
705 p->hide_keyboard_timer = 0;
706
707 QGuiApplication::inputMethod()->hide();
708 p->keyboard_stt = false;
709
710 emit keyboardChanged();
711 }
712 }
713
~AsemanDevices()714 AsemanDevices::~AsemanDevices()
715 {
716 delete p;
717 }
718