1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 BogDan Vatra <bogdan@kde.org> 4 ** Copyright (C) 2016 The Qt Company Ltd. 5 ** Contact: https://www.qt.io/licensing/ 6 ** 7 ** This file is part of the Android port of the Qt Toolkit. 8 ** 9 ** $QT_BEGIN_LICENSE:LGPL$ 10 ** Commercial License Usage 11 ** Licensees holding valid commercial Qt licenses may use this file in 12 ** accordance with the commercial license agreement provided with the 13 ** Software or, alternatively, in accordance with the terms contained in 14 ** a written agreement between you and The Qt Company. For licensing terms 15 ** and conditions see https://www.qt.io/terms-conditions. For further 16 ** information use the contact form at https://www.qt.io/contact-us. 17 ** 18 ** GNU Lesser General Public License Usage 19 ** Alternatively, this file may be used under the terms of the GNU Lesser 20 ** General Public License version 3 as published by the Free Software 21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 22 ** packaging of this file. Please review the following information to 23 ** ensure the GNU Lesser General Public License version 3 requirements 24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 25 ** 26 ** GNU General Public License Usage 27 ** Alternatively, this file may be used under the terms of the GNU 28 ** General Public License version 2.0 or (at your option) the GNU General 29 ** Public license version 3 or any later version approved by the KDE Free 30 ** Qt Foundation. The licenses are as published by the Free Software 31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 32 ** included in the packaging of this file. Please review the following 33 ** information to ensure the GNU General Public License requirements will 34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 35 ** https://www.gnu.org/licenses/gpl-3.0.html. 36 ** 37 ** $QT_END_LICENSE$ 38 ** 39 ****************************************************************************/ 40 41 package org.qtproject.qt5.android; 42 43 import java.io.File; 44 import java.io.FileNotFoundException; 45 import java.util.ArrayList; 46 import java.util.Objects; 47 import java.util.concurrent.Semaphore; 48 import java.io.IOException; 49 import java.util.HashMap; 50 51 import android.app.Activity; 52 import android.app.Service; 53 import android.content.ActivityNotFoundException; 54 import android.content.Context; 55 import android.content.ContentResolver; 56 import android.content.Intent; 57 import android.content.pm.PackageManager; 58 import android.content.pm.ApplicationInfo; 59 import android.content.UriPermission; 60 import android.net.Uri; 61 import android.os.Build; 62 import android.os.Handler; 63 import android.os.IBinder; 64 import android.os.Looper; 65 import android.content.ClipboardManager; 66 import android.content.ClipboardManager.OnPrimaryClipChangedListener; 67 import android.content.ClipData; 68 import android.os.ParcelFileDescriptor; 69 import android.util.Log; 70 import android.view.ContextMenu; 71 import android.view.KeyEvent; 72 import android.view.Menu; 73 import android.view.MotionEvent; 74 import android.view.View; 75 import android.view.InputDevice; 76 import android.database.Cursor; 77 import android.provider.DocumentsContract; 78 79 import java.lang.reflect.Method; 80 import java.security.KeyStore; 81 import java.security.cert.X509Certificate; 82 import java.util.Iterator; 83 import java.util.List; 84 import javax.net.ssl.TrustManagerFactory; 85 import javax.net.ssl.TrustManager; 86 import javax.net.ssl.X509TrustManager; 87 88 public class QtNative 89 { 90 private static Activity m_activity = null; 91 private static boolean m_activityPaused = false; 92 private static Service m_service = null; 93 private static QtActivityDelegate m_activityDelegate = null; 94 private static QtServiceDelegate m_serviceDelegate = null; 95 public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations 96 97 public static final String QtTAG = "Qt JAVA"; // string used for Log.x 98 private static ArrayList<Runnable> m_lostActions = new ArrayList<Runnable>(); // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.) 99 private static boolean m_started = false; 100 private static int m_displayMetricsScreenWidthPixels = 0; 101 private static int m_displayMetricsScreenHeightPixels = 0; 102 private static int m_displayMetricsDesktopWidthPixels = 0; 103 private static int m_displayMetricsDesktopHeightPixels = 0; 104 private static double m_displayMetricsXDpi = .0; 105 private static double m_displayMetricsYDpi = .0; 106 private static double m_displayMetricsScaledDensity = 1.0; 107 private static double m_displayMetricsDensity = 1.0; 108 private static int m_oldx, m_oldy; 109 private static final int m_moveThreshold = 0; 110 private static ClipboardManager m_clipboardManager = null; 111 private static Method m_checkSelfPermissionMethod = null; 112 private static Boolean m_tabletEventSupported = null; 113 private static boolean m_usePrimaryClip = false; 114 public static QtThread m_qtThread = new QtThread(); 115 private static HashMap<String, Uri> m_cachedUris = new HashMap<String, Uri>(); 116 private static ArrayList<String> m_knownDirs = new ArrayList<String>(); 117 private static final String NoPermissionErrorMessage = "No permissions to open Uri"; 118 119 private static final Runnable runPendingCppRunnablesRunnable = new Runnable() { 120 @Override 121 public void run() { 122 runPendingCppRunnables(); 123 } 124 }; 125 126 private static ClassLoader m_classLoader = null; classLoader()127 public static ClassLoader classLoader() 128 { 129 return m_classLoader; 130 } 131 setClassLoader(ClassLoader classLoader)132 public static void setClassLoader(ClassLoader classLoader) 133 { 134 m_classLoader = classLoader; 135 } 136 activity()137 public static Activity activity() 138 { 139 synchronized (m_mainActivityMutex) { 140 return m_activity; 141 } 142 } 143 service()144 public static Service service() 145 { 146 synchronized (m_mainActivityMutex) { 147 return m_service; 148 } 149 } 150 151 activityDelegate()152 public static QtActivityDelegate activityDelegate() 153 { 154 synchronized (m_mainActivityMutex) { 155 return m_activityDelegate; 156 } 157 } 158 serviceDelegate()159 public static QtServiceDelegate serviceDelegate() 160 { 161 synchronized (m_mainActivityMutex) { 162 return m_serviceDelegate; 163 } 164 } 165 getStringArray(String joinedString)166 public static String[] getStringArray(String joinedString) 167 { 168 return joinedString.split(","); 169 } 170 getUriWithValidPermission(Context context, String uri, String openMode)171 private static Uri getUriWithValidPermission(Context context, String uri, String openMode) 172 { 173 try { 174 Uri parsedUri = Uri.parse(uri); 175 String scheme = parsedUri.getScheme(); 176 177 // We only want to check permissions for content Uris 178 if (scheme.compareTo("content") != 0) 179 return parsedUri; 180 181 List<UriPermission> permissions = context.getContentResolver().getPersistedUriPermissions(); 182 String uriStr = parsedUri.getPath(); 183 184 for (int i = 0; i < permissions.size(); ++i) { 185 Uri iterUri = permissions.get(i).getUri(); 186 boolean isRightPermission = permissions.get(i).isReadPermission(); 187 188 if (!openMode.equals("r")) 189 isRightPermission = permissions.get(i).isWritePermission(); 190 191 if (iterUri.getPath().equals(uriStr) && isRightPermission) 192 return iterUri; 193 } 194 195 // if we only have transient permissions on uri all the above will fail, 196 // but we will be able to read the file anyway, so continue with uri here anyway 197 // and check for SecurityExceptions later 198 return parsedUri; 199 } catch (SecurityException e) { 200 e.printStackTrace(); 201 return null; 202 } 203 } 204 openURL(Context context, String url, String mime)205 public static boolean openURL(Context context, String url, String mime) 206 { 207 Uri uri = getUriWithValidPermission(context, url, "r"); 208 209 if (uri == null) { 210 Log.e(QtTAG, "openURL(): No permissions to open Uri"); 211 return false; 212 } 213 214 try { 215 Intent intent = new Intent(Intent.ACTION_VIEW, uri); 216 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 217 if (!mime.isEmpty()) 218 intent.setDataAndType(uri, mime); 219 220 activity().startActivity(intent); 221 222 return true; 223 } catch (IllegalArgumentException e) { 224 Log.e(QtTAG, "openURL(): Invalid Uri"); 225 e.printStackTrace(); 226 return false; 227 } catch (UnsupportedOperationException e) { 228 Log.e(QtTAG, "openURL(): Unsupported operation for given Uri"); 229 e.printStackTrace(); 230 return false; 231 } catch (Exception e) { 232 e.printStackTrace(); 233 return false; 234 } 235 } 236 openFdForContentUrl(Context context, String contentUrl, String openMode)237 public static int openFdForContentUrl(Context context, String contentUrl, String openMode) 238 { 239 Uri uri = m_cachedUris.get(contentUrl); 240 if (uri == null) 241 uri = getUriWithValidPermission(context, contentUrl, openMode); 242 int error = -1; 243 244 if (uri == null) { 245 Log.e(QtTAG, "openFdForContentUrl(): " + NoPermissionErrorMessage); 246 return error; 247 } 248 249 try { 250 ContentResolver resolver = context.getContentResolver(); 251 ParcelFileDescriptor fdDesc = resolver.openFileDescriptor(uri, openMode); 252 return fdDesc.detachFd(); 253 } catch (FileNotFoundException e) { 254 e.printStackTrace(); 255 } catch (IllegalArgumentException e) { 256 Log.e(QtTAG, "openFdForContentUrl(): Invalid Uri"); 257 e.printStackTrace(); 258 } catch (SecurityException e) { 259 Log.e(QtTAG, NoPermissionErrorMessage); 260 } 261 return error; 262 } 263 getSize(Context context, String contentUrl)264 public static long getSize(Context context, String contentUrl) 265 { 266 long size = -1; 267 Uri uri = m_cachedUris.get(contentUrl); 268 if (uri == null) 269 uri = getUriWithValidPermission(context, contentUrl, "r"); 270 271 if (uri == null) { 272 Log.e(QtTAG, NoPermissionErrorMessage); 273 return size; 274 } else if (!m_cachedUris.containsKey(contentUrl)) { 275 m_cachedUris.put(contentUrl, uri); 276 } 277 278 try { 279 ContentResolver resolver = context.getContentResolver(); 280 Cursor cur = resolver.query(uri, new String[] { DocumentsContract.Document.COLUMN_SIZE }, null, null, null); 281 if (cur != null) { 282 if (cur.moveToFirst()) 283 size = cur.getLong(0); 284 cur.close(); 285 } 286 return size; 287 } catch (IllegalArgumentException e) { 288 Log.e(QtTAG, "getSize(): Invalid Uri"); 289 e.printStackTrace(); 290 } catch (UnsupportedOperationException e) { 291 Log.e(QtTAG, "getSize(): Unsupported operation for given Uri"); 292 e.printStackTrace(); 293 } catch (SecurityException e) { 294 Log.e(QtTAG, NoPermissionErrorMessage); 295 } 296 return size; 297 } 298 checkFileExists(Context context, String contentUrl)299 public static boolean checkFileExists(Context context, String contentUrl) 300 { 301 boolean exists = false; 302 Uri uri = m_cachedUris.get(contentUrl); 303 if (uri == null) 304 uri = getUriWithValidPermission(context, contentUrl, "r"); 305 if (uri == null) { 306 Log.e(QtTAG, NoPermissionErrorMessage); 307 return exists; 308 } else { 309 if (!m_cachedUris.containsKey(contentUrl)) 310 m_cachedUris.put(contentUrl, uri); 311 } 312 313 try { 314 ContentResolver resolver = context.getContentResolver(); 315 Cursor cur = resolver.query(uri, null, null, null, null); 316 if (cur != null) { 317 exists = true; 318 cur.close(); 319 } 320 return exists; 321 } catch (IllegalArgumentException e) { 322 Log.e(QtTAG, "checkFileExists(): Invalid Uri"); 323 e.printStackTrace(); 324 } catch (UnsupportedOperationException e) { 325 Log.e(QtTAG, "checkFileExists(): Unsupported operation for given Uri"); 326 e.printStackTrace(); 327 } catch (SecurityException e) { 328 Log.e(QtTAG, NoPermissionErrorMessage); 329 } 330 return exists; 331 } 332 checkIfWritable(Context context, String contentUrl)333 public static boolean checkIfWritable(Context context, String contentUrl) 334 { 335 return getUriWithValidPermission(context, contentUrl, "w") != null; 336 } 337 checkIfDir(Context context, String contentUrl)338 public static boolean checkIfDir(Context context, String contentUrl) 339 { 340 boolean isDir = false; 341 Uri uri = m_cachedUris.get(contentUrl); 342 if (m_knownDirs.contains(contentUrl)) 343 return true; 344 if (uri == null) { 345 uri = getUriWithValidPermission(context, contentUrl, "r"); 346 } 347 if (uri == null) { 348 Log.e(QtTAG, NoPermissionErrorMessage); 349 return isDir; 350 } else { 351 if (!m_cachedUris.containsKey(contentUrl)) 352 m_cachedUris.put(contentUrl, uri); 353 } 354 355 try { 356 final List<String> paths = uri.getPathSegments(); 357 // getTreeDocumentId will throw an exception if it is not a directory so check manually 358 if (!paths.get(0).equals("tree")) 359 return false; 360 ContentResolver resolver = context.getContentResolver(); 361 Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri)); 362 if (!docUri.toString().startsWith(uri.toString())) 363 return false; 364 Cursor cur = resolver.query(docUri, new String[] { DocumentsContract.Document.COLUMN_MIME_TYPE }, null, null, null); 365 if (cur != null) { 366 if (cur.moveToFirst()) { 367 final String dirStr = new String(DocumentsContract.Document.MIME_TYPE_DIR); 368 isDir = cur.getString(0).equals(dirStr); 369 if (isDir) 370 m_knownDirs.add(contentUrl); 371 } 372 cur.close(); 373 } 374 return isDir; 375 } catch (IllegalArgumentException e) { 376 Log.e(QtTAG, "checkIfDir(): Invalid Uri"); 377 e.printStackTrace(); 378 } catch (UnsupportedOperationException e) { 379 Log.e(QtTAG, "checkIfDir(): Unsupported operation for given Uri"); 380 e.printStackTrace(); 381 } catch (SecurityException e) { 382 Log.e(QtTAG, NoPermissionErrorMessage); 383 } 384 return false; 385 } listContentsFromTreeUri(Context context, String contentUrl)386 public static String[] listContentsFromTreeUri(Context context, String contentUrl) 387 { 388 Uri treeUri = Uri.parse(contentUrl); 389 final ArrayList<String> results = new ArrayList<String>(); 390 if (treeUri == null) { 391 Log.e(QtTAG, "listContentsFromTreeUri(): Invalid uri"); 392 return results.toArray(new String[results.size()]); 393 } 394 final ContentResolver resolver = context.getContentResolver(); 395 final Uri docUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, 396 DocumentsContract.getTreeDocumentId(treeUri)); 397 final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(docUri, 398 DocumentsContract.getDocumentId(docUri)); 399 Cursor c = null; 400 final String dirStr = new String(DocumentsContract.Document.MIME_TYPE_DIR); 401 try { 402 c = resolver.query(childrenUri, new String[] { 403 DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE }, null, null, null); 404 while (c.moveToNext()) { 405 final String fileString = c.getString(1); 406 if (!m_cachedUris.containsKey(contentUrl + "/" + fileString)) { 407 m_cachedUris.put(contentUrl + "/" + fileString, 408 DocumentsContract.buildDocumentUriUsingTree(treeUri, c.getString(0))); 409 } 410 results.add(fileString); 411 if (c.getString(2).equals(dirStr)) 412 m_knownDirs.add(contentUrl + "/" + fileString); 413 } 414 c.close(); 415 } catch (Exception e) { 416 Log.w(QtTAG, "Failed query: " + e); 417 return results.toArray(new String[results.size()]); 418 } 419 return results.toArray(new String[results.size()]); 420 } 421 // this method loads full path libs loadQtLibraries(final ArrayList<String> libraries)422 public static void loadQtLibraries(final ArrayList<String> libraries) 423 { 424 m_qtThread.run(new Runnable() { 425 @Override 426 public void run() { 427 if (libraries == null) 428 return; 429 for (String libName : libraries) { 430 try { 431 File f = new File(libName); 432 if (f.exists()) 433 System.load(libName); 434 else 435 Log.i(QtTAG, "Can't find '" + libName + "'"); 436 } catch (SecurityException e) { 437 Log.i(QtTAG, "Can't load '" + libName + "'", e); 438 } catch (Exception e) { 439 Log.i(QtTAG, "Can't load '" + libName + "'", e); 440 } 441 } 442 } 443 }); 444 } 445 446 // this method loads bundled libs by name. loadBundledLibraries(final ArrayList<String> libraries, final String nativeLibraryDir)447 public static void loadBundledLibraries(final ArrayList<String> libraries, final String nativeLibraryDir) 448 { 449 m_qtThread.run(new Runnable() { 450 @Override 451 public void run() { 452 if (libraries == null) 453 return; 454 455 for (String libName : libraries) { 456 try { 457 String libNameTemplate = "lib" + libName + ".so"; 458 File f = new File(nativeLibraryDir + libNameTemplate); 459 if (!f.exists()) { 460 Log.i(QtTAG, "Can't find '" + f.getAbsolutePath()); 461 try { 462 ApplicationInfo info = getContext().getApplicationContext().getPackageManager() 463 .getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA); 464 String systemLibraryDir = QtNativeLibrariesDir.systemLibrariesDir; 465 if (info.metaData.containsKey("android.app.system_libs_prefix")) 466 systemLibraryDir = info.metaData.getString("android.app.system_libs_prefix"); 467 f = new File(systemLibraryDir + libNameTemplate); 468 } catch (Exception e) { 469 e.printStackTrace(); 470 } 471 } 472 if (f.exists()) 473 System.load(f.getAbsolutePath()); 474 else 475 Log.i(QtTAG, "Can't find '" + f.getAbsolutePath()); 476 } catch (Exception e) { 477 Log.i(QtTAG, "Can't load '" + libName + "'", e); 478 } 479 } 480 } 481 }); 482 } 483 loadMainLibrary(final String mainLibrary, final String nativeLibraryDir)484 public static String loadMainLibrary(final String mainLibrary, final String nativeLibraryDir) 485 { 486 final String[] res = new String[1]; 487 res[0] = null; 488 m_qtThread.run(new Runnable() { 489 @Override 490 public void run() { 491 try { 492 String mainLibNameTemplate = "lib" + mainLibrary + ".so"; 493 File f = new File(nativeLibraryDir + mainLibNameTemplate); 494 if (!f.exists()) { 495 try { 496 ApplicationInfo info = getContext().getApplicationContext().getPackageManager() 497 .getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA); 498 String systemLibraryDir = QtNativeLibrariesDir.systemLibrariesDir; 499 if (info.metaData.containsKey("android.app.system_libs_prefix")) 500 systemLibraryDir = info.metaData.getString("android.app.system_libs_prefix"); 501 f = new File(systemLibraryDir + mainLibNameTemplate); 502 } catch (Exception e) { 503 e.printStackTrace(); 504 return; 505 } 506 } 507 if (!f.exists()) 508 return; 509 System.load(f.getAbsolutePath()); 510 res[0] = f.getAbsolutePath(); 511 } catch (Exception e) { 512 Log.e(QtTAG, "Can't load '" + mainLibrary + "'", e); 513 } 514 } 515 }); 516 return res[0]; 517 } 518 setActivity(Activity qtMainActivity, QtActivityDelegate qtActivityDelegate)519 public static void setActivity(Activity qtMainActivity, QtActivityDelegate qtActivityDelegate) 520 { 521 synchronized (m_mainActivityMutex) { 522 m_activity = qtMainActivity; 523 m_activityDelegate = qtActivityDelegate; 524 } 525 } 526 setService(Service qtMainService, QtServiceDelegate qtServiceDelegate)527 public static void setService(Service qtMainService, QtServiceDelegate qtServiceDelegate) 528 { 529 synchronized (m_mainActivityMutex) { 530 m_service = qtMainService; 531 m_serviceDelegate = qtServiceDelegate; 532 } 533 } 534 setApplicationState(int state)535 public static void setApplicationState(int state) 536 { 537 synchronized (m_mainActivityMutex) { 538 switch (state) { 539 case QtActivityDelegate.ApplicationActive: 540 m_activityPaused = false; 541 Iterator<Runnable> itr = m_lostActions.iterator(); 542 while (itr.hasNext()) 543 runAction(itr.next()); 544 m_lostActions.clear(); 545 break; 546 default: 547 m_activityPaused = true; 548 break; 549 } 550 } 551 updateApplicationState(state); 552 } 553 runAction(Runnable action)554 private static void runAction(Runnable action) 555 { 556 synchronized (m_mainActivityMutex) { 557 final Looper mainLooper = Looper.getMainLooper(); 558 final Handler handler = new Handler(mainLooper); 559 final boolean actionIsQueued = !m_activityPaused && m_activity != null && mainLooper != null && handler.post(action); 560 if (!actionIsQueued) 561 m_lostActions.add(action); 562 } 563 } 564 runPendingCppRunnablesOnAndroidThread()565 private static void runPendingCppRunnablesOnAndroidThread() 566 { 567 synchronized (m_mainActivityMutex) { 568 if (m_activity != null) { 569 if (!m_activityPaused) 570 m_activity.runOnUiThread(runPendingCppRunnablesRunnable); 571 else 572 runAction(runPendingCppRunnablesRunnable); 573 } else { 574 final Looper mainLooper = Looper.getMainLooper(); 575 final Thread looperThread = mainLooper.getThread(); 576 if (looperThread.equals(Thread.currentThread())) { 577 runPendingCppRunnablesRunnable.run(); 578 } else { 579 final Handler handler = new Handler(mainLooper); 580 handler.post(runPendingCppRunnablesRunnable); 581 } 582 } 583 } 584 } 585 setViewVisibility(final View view, final boolean visible)586 private static void setViewVisibility(final View view, final boolean visible) 587 { 588 runAction(new Runnable() { 589 @Override 590 public void run() { 591 view.setVisibility(visible ? View.VISIBLE : View.GONE); 592 } 593 }); 594 } 595 startApplication(String params, final String environment, String mainLib)596 public static boolean startApplication(String params, final String environment, String mainLib) throws Exception 597 { 598 if (params == null) 599 params = "-platform\tandroid"; 600 601 final boolean[] res = new boolean[1]; 602 res[0] = false; 603 synchronized (m_mainActivityMutex) { 604 if (params.length() > 0 && !params.startsWith("\t")) 605 params = "\t" + params; 606 final String qtParams = mainLib + params; 607 m_qtThread.run(new Runnable() { 608 @Override 609 public void run() { 610 res[0] = startQtAndroidPlugin(qtParams, environment); 611 setDisplayMetrics(m_displayMetricsScreenWidthPixels, 612 m_displayMetricsScreenHeightPixels, 613 m_displayMetricsDesktopWidthPixels, 614 m_displayMetricsDesktopHeightPixels, 615 m_displayMetricsXDpi, 616 m_displayMetricsYDpi, 617 m_displayMetricsScaledDensity, 618 m_displayMetricsDensity); 619 } 620 }); 621 m_qtThread.post(new Runnable() { 622 @Override 623 public void run() { 624 startQtApplication(); 625 } 626 }); 627 waitForServiceSetup(); 628 m_started = true; 629 } 630 return res[0]; 631 } 632 setApplicationDisplayMetrics(int screenWidthPixels, int screenHeightPixels, int desktopWidthPixels, int desktopHeightPixels, double XDpi, double YDpi, double scaledDensity, double density)633 public static void setApplicationDisplayMetrics(int screenWidthPixels, 634 int screenHeightPixels, 635 int desktopWidthPixels, 636 int desktopHeightPixels, 637 double XDpi, 638 double YDpi, 639 double scaledDensity, 640 double density) 641 { 642 /* Fix buggy dpi report */ 643 if (XDpi < android.util.DisplayMetrics.DENSITY_LOW) 644 XDpi = android.util.DisplayMetrics.DENSITY_LOW; 645 if (YDpi < android.util.DisplayMetrics.DENSITY_LOW) 646 YDpi = android.util.DisplayMetrics.DENSITY_LOW; 647 648 synchronized (m_mainActivityMutex) { 649 if (m_started) { 650 setDisplayMetrics(screenWidthPixels, 651 screenHeightPixels, 652 desktopWidthPixels, 653 desktopHeightPixels, 654 XDpi, 655 YDpi, 656 scaledDensity, 657 density); 658 } else { 659 m_displayMetricsScreenWidthPixels = screenWidthPixels; 660 m_displayMetricsScreenHeightPixels = screenHeightPixels; 661 m_displayMetricsDesktopWidthPixels = desktopWidthPixels; 662 m_displayMetricsDesktopHeightPixels = desktopHeightPixels; 663 m_displayMetricsXDpi = XDpi; 664 m_displayMetricsYDpi = YDpi; 665 m_displayMetricsScaledDensity = scaledDensity; 666 m_displayMetricsDensity = density; 667 } 668 } 669 } 670 671 672 673 // application methods startQtAndroidPlugin(String params, String env)674 public static native boolean startQtAndroidPlugin(String params, String env); startQtApplication()675 public static native void startQtApplication(); waitForServiceSetup()676 public static native void waitForServiceSetup(); quitQtCoreApplication()677 public static native void quitQtCoreApplication(); quitQtAndroidPlugin()678 public static native void quitQtAndroidPlugin(); terminateQt()679 public static native void terminateQt(); 680 // application methods 681 quitApp()682 private static void quitApp() 683 { 684 runAction(new Runnable() { 685 @Override 686 public void run() { 687 quitQtAndroidPlugin(); 688 if (m_activity != null) 689 m_activity.finish(); 690 if (m_service != null) 691 m_service.stopSelf(); 692 } 693 }); 694 } 695 696 //@ANDROID-9 getAction(int index, MotionEvent event)697 static private int getAction(int index, MotionEvent event) 698 { 699 int action = event.getActionMasked(); 700 if (action == MotionEvent.ACTION_MOVE) { 701 int hsz = event.getHistorySize(); 702 if (hsz > 0) { 703 float x = event.getX(index); 704 float y = event.getY(index); 705 for (int h = 0; h < hsz; ++h) { 706 if ( event.getHistoricalX(index, h) != x || 707 event.getHistoricalY(index, h) != y ) 708 return 1; 709 } 710 return 2; 711 } 712 return 1; 713 } 714 if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) { 715 return 0; 716 } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) { 717 return 3; 718 } 719 return 2; 720 } 721 //@ANDROID-9 722 sendTouchEvent(MotionEvent event, int id)723 static public void sendTouchEvent(MotionEvent event, int id) 724 { 725 int pointerType = 0; 726 727 if (m_tabletEventSupported == null) 728 m_tabletEventSupported = isTabletEventSupported(); 729 730 switch (event.getToolType(0)) { 731 case MotionEvent.TOOL_TYPE_STYLUS: 732 pointerType = 1; // QTabletEvent::Pen 733 break; 734 case MotionEvent.TOOL_TYPE_ERASER: 735 pointerType = 3; // QTabletEvent::Eraser 736 break; 737 } 738 739 if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { 740 sendMouseEvent(event, id); 741 } else if (m_tabletEventSupported && pointerType != 0) { 742 tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getAction(), pointerType, 743 event.getButtonState(), event.getX(), event.getY(), event.getPressure()); 744 } else { 745 touchBegin(id); 746 for (int i = 0; i < event.getPointerCount(); ++i) { 747 touchAdd(id, 748 event.getPointerId(i), 749 getAction(i, event), 750 i == 0, 751 (int)event.getX(i), 752 (int)event.getY(i), 753 event.getTouchMajor(i), 754 event.getTouchMinor(i), 755 event.getOrientation(i), 756 event.getPressure(i)); 757 } 758 759 switch (event.getAction()) { 760 case MotionEvent.ACTION_DOWN: 761 touchEnd(id, 0); 762 break; 763 764 case MotionEvent.ACTION_UP: 765 touchEnd(id, 2); 766 break; 767 768 default: 769 touchEnd(id, 1); 770 } 771 } 772 } 773 sendTrackballEvent(MotionEvent event, int id)774 static public void sendTrackballEvent(MotionEvent event, int id) 775 { 776 sendMouseEvent(event,id); 777 } 778 sendGenericMotionEvent(MotionEvent event, int id)779 static public boolean sendGenericMotionEvent(MotionEvent event, int id) 780 { 781 if (((event.getAction() & (MotionEvent.ACTION_SCROLL | MotionEvent.ACTION_HOVER_MOVE)) == 0) 782 || (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != InputDevice.SOURCE_CLASS_POINTER) { 783 return false; 784 } 785 786 return sendMouseEvent(event, id); 787 } 788 sendMouseEvent(MotionEvent event, int id)789 static public boolean sendMouseEvent(MotionEvent event, int id) 790 { 791 switch (event.getActionMasked()) { 792 case MotionEvent.ACTION_UP: 793 mouseUp(id, (int) event.getX(), (int) event.getY()); 794 break; 795 796 case MotionEvent.ACTION_DOWN: 797 mouseDown(id, (int) event.getX(), (int) event.getY()); 798 m_oldx = (int) event.getX(); 799 m_oldy = (int) event.getY(); 800 break; 801 case MotionEvent.ACTION_HOVER_MOVE: 802 case MotionEvent.ACTION_MOVE: 803 if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) { 804 mouseMove(id, (int) event.getX(), (int) event.getY()); 805 } else { 806 int dx = (int) (event.getX() - m_oldx); 807 int dy = (int) (event.getY() - m_oldy); 808 if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { 809 mouseMove(id, (int) event.getX(), (int) event.getY()); 810 m_oldx = (int) event.getX(); 811 m_oldy = (int) event.getY(); 812 } 813 } 814 break; 815 case MotionEvent.ACTION_SCROLL: 816 mouseWheel(id, (int) event.getX(), (int) event.getY(), 817 event.getAxisValue(MotionEvent.AXIS_HSCROLL), event.getAxisValue(MotionEvent.AXIS_VSCROLL)); 818 break; 819 default: 820 return false; 821 } 822 return true; 823 } 824 getContext()825 public static Context getContext() { 826 if (m_activity != null) 827 return m_activity; 828 return m_service; 829 } 830 checkSelfPermission(String permission)831 public static int checkSelfPermission(String permission) 832 { 833 int perm = PackageManager.PERMISSION_DENIED; 834 synchronized (m_mainActivityMutex) { 835 Context context = getContext(); 836 try { 837 if (Build.VERSION.SDK_INT >= 23) { 838 if (m_checkSelfPermissionMethod == null) 839 m_checkSelfPermissionMethod = Context.class.getMethod("checkSelfPermission", String.class); 840 perm = (Integer)m_checkSelfPermissionMethod.invoke(context, permission); 841 } else { 842 final PackageManager pm = context.getPackageManager(); 843 perm = pm.checkPermission(permission, context.getApplicationContext().getPackageName()); 844 } 845 } catch (Exception e) { 846 e.printStackTrace(); 847 } 848 } 849 850 return perm; 851 } 852 updateSelection(final int selStart, final int selEnd, final int candidatesStart, final int candidatesEnd)853 private static void updateSelection(final int selStart, 854 final int selEnd, 855 final int candidatesStart, 856 final int candidatesEnd) 857 { 858 runAction(new Runnable() { 859 @Override 860 public void run() { 861 if (m_activityDelegate != null) 862 m_activityDelegate.updateSelection(selStart, selEnd, candidatesStart, candidatesEnd); 863 } 864 }); 865 } 866 updateHandles(final int mode, final int editX, final int editY, final int editButtons, final int x1, final int y1, final int x2, final int y2, final boolean rtl)867 private static void updateHandles(final int mode, 868 final int editX, 869 final int editY, 870 final int editButtons, 871 final int x1, 872 final int y1, 873 final int x2, 874 final int y2, 875 final boolean rtl) 876 { 877 runAction(new Runnable() { 878 @Override 879 public void run() { 880 m_activityDelegate.updateHandles(mode, editX, editY, editButtons, x1, y1, x2, y2, rtl); 881 } 882 }); 883 } 884 showSoftwareKeyboard(final int x, final int y, final int width, final int height, final int inputHints, final int enterKeyType)885 private static void showSoftwareKeyboard(final int x, 886 final int y, 887 final int width, 888 final int height, 889 final int inputHints, 890 final int enterKeyType) 891 { 892 runAction(new Runnable() { 893 @Override 894 public void run() { 895 if (m_activityDelegate != null) 896 m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); 897 } 898 }); 899 } 900 resetSoftwareKeyboard()901 private static void resetSoftwareKeyboard() 902 { 903 runAction(new Runnable() { 904 @Override 905 public void run() { 906 if (m_activityDelegate != null) 907 m_activityDelegate.resetSoftwareKeyboard(); 908 } 909 }); 910 } 911 hideSoftwareKeyboard()912 private static void hideSoftwareKeyboard() 913 { 914 runAction(new Runnable() { 915 @Override 916 public void run() { 917 if (m_activityDelegate != null) 918 m_activityDelegate.hideSoftwareKeyboard(); 919 } 920 }); 921 } 922 setFullScreen(final boolean fullScreen)923 private static void setFullScreen(final boolean fullScreen) 924 { 925 runAction(new Runnable() { 926 @Override 927 public void run() { 928 if (m_activityDelegate != null) { 929 m_activityDelegate.setFullScreen(fullScreen); 930 } 931 updateWindow(); 932 } 933 }); 934 } 935 notifyAccessibilityLocationChange()936 private static void notifyAccessibilityLocationChange() 937 { 938 runAction(new Runnable() { 939 @Override 940 public void run() { 941 if (m_activityDelegate != null) { 942 m_activityDelegate.notifyAccessibilityLocationChange(); 943 } 944 } 945 }); 946 } 947 notifyObjectHide(final int viewId)948 private static void notifyObjectHide(final int viewId) 949 { 950 runAction(new Runnable() { 951 @Override 952 public void run() { 953 if (m_activityDelegate != null) { 954 m_activityDelegate.notifyObjectHide(viewId); 955 } 956 } 957 }); 958 } 959 notifyObjectFocus(final int viewId)960 private static void notifyObjectFocus(final int viewId) 961 { 962 runAction(new Runnable() { 963 @Override 964 public void run() { 965 if (m_activityDelegate != null) { 966 m_activityDelegate.notifyObjectFocus(viewId); 967 } 968 } 969 }); 970 } 971 registerClipboardManager()972 private static void registerClipboardManager() 973 { 974 if (m_service == null || m_activity != null) { // Avoid freezing if only service 975 final Semaphore semaphore = new Semaphore(0); 976 runAction(new Runnable() { 977 @Override 978 public void run() { 979 if (m_activity != null) 980 m_clipboardManager = (android.content.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE); 981 if (m_clipboardManager != null) { 982 m_clipboardManager.addPrimaryClipChangedListener(new ClipboardManager.OnPrimaryClipChangedListener() { 983 public void onPrimaryClipChanged() { 984 onClipboardDataChanged(); 985 } 986 }); 987 } 988 semaphore.release(); 989 } 990 }); 991 try { 992 semaphore.acquire(); 993 } catch (Exception e) { 994 e.printStackTrace(); 995 } 996 } 997 } 998 clearClipData()999 private static void clearClipData() 1000 { 1001 if (Build.VERSION.SDK_INT >= 28 && m_clipboardManager != null) 1002 m_clipboardManager.clearPrimaryClip(); 1003 } setClipboardText(String text)1004 private static void setClipboardText(String text) 1005 { 1006 if (m_clipboardManager != null) { 1007 ClipData clipData = ClipData.newPlainText("text/plain", text); 1008 updatePrimaryClip(clipData); 1009 } 1010 } 1011 hasClipboardText()1012 public static boolean hasClipboardText() 1013 { 1014 try { 1015 if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { 1016 ClipData primaryClip = m_clipboardManager.getPrimaryClip(); 1017 for (int i = 0; i < primaryClip.getItemCount(); ++i) 1018 if (primaryClip.getItemAt(i).getText() != null) 1019 return true; 1020 } 1021 } catch (Exception e) { 1022 Log.e(QtTAG, "Failed to get clipboard data", e); 1023 } 1024 return false; 1025 } 1026 getClipboardText()1027 private static String getClipboardText() 1028 { 1029 try { 1030 if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { 1031 ClipData primaryClip = m_clipboardManager.getPrimaryClip(); 1032 for (int i = 0; i < primaryClip.getItemCount(); ++i) 1033 if (primaryClip.getItemAt(i).getText() != null) 1034 return primaryClip.getItemAt(i).getText().toString(); 1035 } 1036 } catch (Exception e) { 1037 Log.e(QtTAG, "Failed to get clipboard data", e); 1038 } 1039 return ""; 1040 } 1041 updatePrimaryClip(ClipData clipData)1042 private static void updatePrimaryClip(ClipData clipData) 1043 { 1044 try { 1045 if (m_usePrimaryClip) { 1046 ClipData clip = m_clipboardManager.getPrimaryClip(); 1047 if (Build.VERSION.SDK_INT >= 26) { 1048 Objects.requireNonNull(clip).addItem(m_activity.getContentResolver(), clipData.getItemAt(0)); 1049 } else { 1050 Objects.requireNonNull(clip).addItem(clipData.getItemAt(0)); 1051 } 1052 m_clipboardManager.setPrimaryClip(clip); 1053 } else { 1054 m_clipboardManager.setPrimaryClip(clipData); 1055 m_usePrimaryClip = true; 1056 } 1057 } catch (Exception e) { 1058 Log.e(QtTAG, "Failed to set clipboard data", e); 1059 } 1060 } 1061 setClipboardHtml(String text, String html)1062 private static void setClipboardHtml(String text, String html) 1063 { 1064 if (m_clipboardManager != null) { 1065 ClipData clipData = ClipData.newHtmlText("text/html", text, html); 1066 updatePrimaryClip(clipData); 1067 } 1068 } 1069 hasClipboardHtml()1070 public static boolean hasClipboardHtml() 1071 { 1072 try { 1073 if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { 1074 ClipData primaryClip = m_clipboardManager.getPrimaryClip(); 1075 for (int i = 0; i < Objects.requireNonNull(primaryClip).getItemCount(); ++i) 1076 if (primaryClip.getItemAt(i).getHtmlText() != null) 1077 return true; 1078 } 1079 } catch (Exception e) { 1080 Log.e(QtTAG, "Failed to get clipboard data", e); 1081 } 1082 return false; 1083 } 1084 getClipboardHtml()1085 private static String getClipboardHtml() 1086 { 1087 try { 1088 if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { 1089 ClipData primaryClip = m_clipboardManager.getPrimaryClip(); 1090 for (int i = 0; i < primaryClip.getItemCount(); ++i) 1091 if (primaryClip.getItemAt(i).getHtmlText() != null) 1092 return primaryClip.getItemAt(i).getHtmlText().toString(); 1093 } 1094 } catch (Exception e) { 1095 Log.e(QtTAG, "Failed to get clipboard data", e); 1096 } 1097 return ""; 1098 } 1099 setClipboardUri(String uriString)1100 private static void setClipboardUri(String uriString) 1101 { 1102 if (m_clipboardManager != null) { 1103 ClipData clipData = ClipData.newUri(m_activity.getContentResolver(), "text/uri-list", 1104 Uri.parse(uriString)); 1105 updatePrimaryClip(clipData); 1106 } 1107 } 1108 hasClipboardUri()1109 public static boolean hasClipboardUri() 1110 { 1111 try { 1112 if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { 1113 ClipData primaryClip = m_clipboardManager.getPrimaryClip(); 1114 for (int i = 0; i < primaryClip.getItemCount(); ++i) 1115 if (primaryClip.getItemAt(i).getUri() != null) 1116 return true; 1117 } 1118 } catch (Exception e) { 1119 Log.e(QtTAG, "Failed to get clipboard data", e); 1120 } 1121 return false; 1122 } 1123 getClipboardUris()1124 private static String[] getClipboardUris() 1125 { 1126 ArrayList<String> uris = new ArrayList<String>(); 1127 try { 1128 if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { 1129 ClipData primaryClip = m_clipboardManager.getPrimaryClip(); 1130 for (int i = 0; i < primaryClip.getItemCount(); ++i) 1131 if (primaryClip.getItemAt(i).getUri() != null) 1132 uris.add(primaryClip.getItemAt(i).getUri().toString()); 1133 } 1134 } catch (Exception e) { 1135 Log.e(QtTAG, "Failed to get clipboard data", e); 1136 } 1137 String[] strings = new String[uris.size()]; 1138 strings = uris.toArray(strings); 1139 return strings; 1140 } 1141 openContextMenu(final int x, final int y, final int w, final int h)1142 private static void openContextMenu(final int x, final int y, final int w, final int h) 1143 { 1144 runAction(new Runnable() { 1145 @Override 1146 public void run() { 1147 if (m_activityDelegate != null) 1148 m_activityDelegate.openContextMenu(x, y, w, h); 1149 } 1150 }); 1151 } 1152 closeContextMenu()1153 private static void closeContextMenu() 1154 { 1155 runAction(new Runnable() { 1156 @Override 1157 public void run() { 1158 if (m_activityDelegate != null) 1159 m_activityDelegate.closeContextMenu(); 1160 } 1161 }); 1162 } 1163 resetOptionsMenu()1164 private static void resetOptionsMenu() 1165 { 1166 runAction(new Runnable() { 1167 @Override 1168 public void run() { 1169 if (m_activityDelegate != null) 1170 m_activityDelegate.resetOptionsMenu(); 1171 } 1172 }); 1173 } 1174 openOptionsMenu()1175 private static void openOptionsMenu() 1176 { 1177 runAction(new Runnable() { 1178 @Override 1179 public void run() { 1180 if (m_activity != null) 1181 m_activity.openOptionsMenu(); 1182 } 1183 }); 1184 } 1185 getSSLCertificates()1186 private static byte[][] getSSLCertificates() 1187 { 1188 ArrayList<byte[]> certificateList = new ArrayList<byte[]>(); 1189 1190 try { 1191 TrustManagerFactory factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 1192 factory.init((KeyStore) null); 1193 1194 for (TrustManager manager : factory.getTrustManagers()) { 1195 if (manager instanceof X509TrustManager) { 1196 X509TrustManager trustManager = (X509TrustManager) manager; 1197 1198 for (X509Certificate certificate : trustManager.getAcceptedIssuers()) { 1199 byte buffer[] = certificate.getEncoded(); 1200 certificateList.add(buffer); 1201 } 1202 } 1203 } 1204 } catch (Exception e) { 1205 Log.e(QtTAG, "Failed to get certificates", e); 1206 } 1207 1208 byte[][] certificateArray = new byte[certificateList.size()][]; 1209 certificateArray = certificateList.toArray(certificateArray); 1210 return certificateArray; 1211 } 1212 createSurface(final int id, final boolean onTop, final int x, final int y, final int w, final int h, final int imageDepth)1213 private static void createSurface(final int id, final boolean onTop, final int x, final int y, final int w, final int h, final int imageDepth) 1214 { 1215 runAction(new Runnable() { 1216 @Override 1217 public void run() { 1218 if (m_activityDelegate != null) 1219 m_activityDelegate.createSurface(id, onTop, x, y, w, h, imageDepth); 1220 } 1221 }); 1222 } 1223 insertNativeView(final int id, final View view, final int x, final int y, final int w, final int h)1224 private static void insertNativeView(final int id, final View view, final int x, final int y, final int w, final int h) 1225 { 1226 runAction(new Runnable() { 1227 @Override 1228 public void run() { 1229 if (m_activityDelegate != null) 1230 m_activityDelegate.insertNativeView(id, view, x, y, w, h); 1231 } 1232 }); 1233 } 1234 setSurfaceGeometry(final int id, final int x, final int y, final int w, final int h)1235 private static void setSurfaceGeometry(final int id, final int x, final int y, final int w, final int h) 1236 { 1237 runAction(new Runnable() { 1238 @Override 1239 public void run() { 1240 if (m_activityDelegate != null) 1241 m_activityDelegate.setSurfaceGeometry(id, x, y, w, h); 1242 } 1243 }); 1244 } 1245 bringChildToFront(final int id)1246 private static void bringChildToFront(final int id) 1247 { 1248 runAction(new Runnable() { 1249 @Override 1250 public void run() { 1251 if (m_activityDelegate != null) 1252 m_activityDelegate.bringChildToFront(id); 1253 } 1254 }); 1255 } 1256 bringChildToBack(final int id)1257 private static void bringChildToBack(final int id) 1258 { 1259 runAction(new Runnable() { 1260 @Override 1261 public void run() { 1262 if (m_activityDelegate != null) 1263 m_activityDelegate.bringChildToBack(id); 1264 } 1265 }); 1266 } 1267 destroySurface(final int id)1268 private static void destroySurface(final int id) 1269 { 1270 runAction(new Runnable() { 1271 @Override 1272 public void run() { 1273 if (m_activityDelegate != null) 1274 m_activityDelegate.destroySurface(id); 1275 } 1276 }); 1277 } 1278 initializeAccessibility()1279 private static void initializeAccessibility() 1280 { 1281 runAction(new Runnable() { 1282 @Override 1283 public void run() { 1284 m_activityDelegate.initializeAccessibility(); 1285 } 1286 }); 1287 } 1288 hideSplashScreen(final int duration)1289 private static void hideSplashScreen(final int duration) 1290 { 1291 runAction(new Runnable() { 1292 @Override 1293 public void run() { 1294 if (m_activityDelegate != null) 1295 m_activityDelegate.hideSplashScreen(duration); 1296 } 1297 }); 1298 } 1299 listAssetContent(android.content.res.AssetManager asset, String path)1300 private static String[] listAssetContent(android.content.res.AssetManager asset, String path) { 1301 String [] list; 1302 ArrayList<String> res = new ArrayList<String>(); 1303 try { 1304 list = asset.list(path); 1305 if (list.length > 0) { 1306 for (String file : list) { 1307 try { 1308 String[] isDir = asset.list(path.length() > 0 ? path + "/" + file : file); 1309 if (isDir != null && isDir.length > 0) 1310 file += "/"; 1311 res.add(file); 1312 } catch (Exception e) { 1313 e.printStackTrace(); 1314 } 1315 } 1316 } 1317 } catch (Exception e) { 1318 e.printStackTrace(); 1319 } 1320 return res.toArray(new String[res.size()]); 1321 } 1322 1323 // screen methods setDisplayMetrics(int screenWidthPixels, int screenHeightPixels, int desktopWidthPixels, int desktopHeightPixels, double XDpi, double YDpi, double scaledDensity, double density)1324 public static native void setDisplayMetrics(int screenWidthPixels, 1325 int screenHeightPixels, 1326 int desktopWidthPixels, 1327 int desktopHeightPixels, 1328 double XDpi, 1329 double YDpi, 1330 double scaledDensity, 1331 double density); handleOrientationChanged(int newRotation, int nativeOrientation)1332 public static native void handleOrientationChanged(int newRotation, int nativeOrientation); 1333 // screen methods 1334 1335 // pointer methods mouseDown(int winId, int x, int y)1336 public static native void mouseDown(int winId, int x, int y); mouseUp(int winId, int x, int y)1337 public static native void mouseUp(int winId, int x, int y); mouseMove(int winId, int x, int y)1338 public static native void mouseMove(int winId, int x, int y); mouseWheel(int winId, int x, int y, float hdelta, float vdelta)1339 public static native void mouseWheel(int winId, int x, int y, float hdelta, float vdelta); touchBegin(int winId)1340 public static native void touchBegin(int winId); touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float major, float minor, float rotation, float pressure)1341 public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float major, float minor, float rotation, float pressure); touchEnd(int winId, int action)1342 public static native void touchEnd(int winId, int action); longPress(int winId, int x, int y)1343 public static native void longPress(int winId, int x, int y); 1344 // pointer methods 1345 1346 // tablet methods isTabletEventSupported()1347 public static native boolean isTabletEventSupported(); tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure)1348 public static native void tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure); 1349 // tablet methods 1350 1351 // keyboard methods keyDown(int key, int unicode, int modifier, boolean autoRepeat)1352 public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat); keyUp(int key, int unicode, int modifier, boolean autoRepeat)1353 public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat); keyboardVisibilityChanged(boolean visibility)1354 public static native void keyboardVisibilityChanged(boolean visibility); keyboardGeometryChanged(int x, int y, int width, int height)1355 public static native void keyboardGeometryChanged(int x, int y, int width, int height); 1356 // keyboard methods 1357 1358 // handle methods 1359 public static final int IdCursorHandle = 1; 1360 public static final int IdLeftHandle = 2; 1361 public static final int IdRightHandle = 3; handleLocationChanged(int id, int x, int y)1362 public static native void handleLocationChanged(int id, int x, int y); 1363 // handle methods 1364 1365 // dispatch events methods dispatchGenericMotionEvent(MotionEvent ev)1366 public static native boolean dispatchGenericMotionEvent(MotionEvent ev); dispatchKeyEvent(KeyEvent event)1367 public static native boolean dispatchKeyEvent(KeyEvent event); 1368 // dispatch events methods 1369 1370 // surface methods setSurface(int id, Object surface, int w, int h)1371 public static native void setSurface(int id, Object surface, int w, int h); 1372 // surface methods 1373 1374 // window methods updateWindow()1375 public static native void updateWindow(); 1376 // window methods 1377 1378 // application methods updateApplicationState(int state)1379 public static native void updateApplicationState(int state); 1380 1381 // menu methods onPrepareOptionsMenu(Menu menu)1382 public static native boolean onPrepareOptionsMenu(Menu menu); onOptionsItemSelected(int itemId, boolean checked)1383 public static native boolean onOptionsItemSelected(int itemId, boolean checked); onOptionsMenuClosed(Menu menu)1384 public static native void onOptionsMenuClosed(Menu menu); 1385 onCreateContextMenu(ContextMenu menu)1386 public static native void onCreateContextMenu(ContextMenu menu); fillContextMenu(Menu menu)1387 public static native void fillContextMenu(Menu menu); onContextItemSelected(int itemId, boolean checked)1388 public static native boolean onContextItemSelected(int itemId, boolean checked); onContextMenuClosed(Menu menu)1389 public static native void onContextMenuClosed(Menu menu); 1390 // menu methods 1391 1392 // clipboard methods onClipboardDataChanged()1393 public static native void onClipboardDataChanged(); 1394 // clipboard methods 1395 1396 // activity methods onActivityResult(int requestCode, int resultCode, Intent data)1397 public static native void onActivityResult(int requestCode, int resultCode, Intent data); onNewIntent(Intent data)1398 public static native void onNewIntent(Intent data); 1399 runPendingCppRunnables()1400 public static native void runPendingCppRunnables(); 1401 sendRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)1402 public static native void sendRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults); 1403 setNativeActivity(Activity activity)1404 private static native void setNativeActivity(Activity activity); setNativeService(Service service)1405 private static native void setNativeService(Service service); 1406 // activity methods 1407 1408 // service methods onBind(Intent intent)1409 public static native IBinder onBind(Intent intent); 1410 // service methods 1411 } 1412