diff options
Diffstat (limited to 'src/android/jar/src/org/qtproject/qt5/android/QtNative.java')
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/QtNative.java | 333 |
1 files changed, 98 insertions, 235 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index dbd356f7a5..41ba50e964 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -45,8 +45,6 @@ import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Semaphore; -import java.io.IOException; -import java.util.HashMap; import android.app.Activity; import android.app.Service; @@ -65,6 +63,7 @@ import android.os.Looper; import android.content.ClipboardManager; import android.content.ClipboardManager.OnPrimaryClipChangedListener; import android.content.ClipData; +import android.content.ClipDescription; import android.os.ParcelFileDescriptor; import android.util.Log; import android.view.ContextMenu; @@ -97,10 +96,12 @@ public class QtNative public static final String QtTAG = "Qt JAVA"; // string used for Log.x 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.) private static boolean m_started = false; + private static boolean m_isKeyboardHiding = false; private static int m_displayMetricsScreenWidthPixels = 0; private static int m_displayMetricsScreenHeightPixels = 0; private static int m_displayMetricsDesktopWidthPixels = 0; private static int m_displayMetricsDesktopHeightPixels = 0; + private static float m_displayMetricsRefreshRate = 60; private static double m_displayMetricsXDpi = .0; private static double m_displayMetricsYDpi = .0; private static double m_displayMetricsScaledDensity = 1.0; @@ -112,8 +113,6 @@ public class QtNative private static Boolean m_tabletEventSupported = null; private static boolean m_usePrimaryClip = false; public static QtThread m_qtThread = new QtThread(); - private static HashMap<String, Uri> m_cachedUris = new HashMap<String, Uri>(); - private static ArrayList<String> m_knownDirs = new ArrayList<String>(); private static final Runnable runPendingCppRunnablesRunnable = new Runnable() { @Override @@ -122,6 +121,13 @@ public class QtNative } }; + public static boolean isStarted() + { + boolean hasActivity = m_activity != null && m_activityDelegate != null; + boolean hasService = m_service != null && m_serviceDelegate != null; + return m_started && (hasActivity || hasService); + } + private static ClassLoader m_classLoader = null; public static ClassLoader classLoader() { @@ -191,11 +197,10 @@ public class QtNative return iterUri; } - // Android 6 and earlier could still manage to open the file so we can return the - // parsed uri here - if (Build.VERSION.SDK_INT < 24) - return parsedUri; - return null; + // if we only have transient permissions on uri all the above will fail, + // but we will be able to read the file anyway, so continue with uri here anyway + // and check for SecurityExceptions later + return parsedUri; } catch (SecurityException e) { e.printStackTrace(); return null; @@ -234,186 +239,6 @@ public class QtNative } } - public static int openFdForContentUrl(Context context, String contentUrl, String openMode) - { - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, openMode); - int error = -1; - - if (uri == null) { - Log.e(QtTAG, "openFdForContentUrl(): No permissions to open Uri"); - return error; - } - - try { - ContentResolver resolver = context.getContentResolver(); - ParcelFileDescriptor fdDesc = resolver.openFileDescriptor(uri, openMode); - return fdDesc.detachFd(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return error; - } catch (IllegalArgumentException e) { - Log.e(QtTAG, "openFdForContentUrl(): Invalid Uri"); - e.printStackTrace(); - return error; - } - } - - public static long getSize(Context context, String contentUrl) - { - long size = -1; - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, "r"); - - if (uri == null) { - Log.e(QtTAG, "getSize(): No permissions to open Uri"); - return size; - } else if (!m_cachedUris.containsKey(contentUrl)) { - m_cachedUris.put(contentUrl, uri); - } - - try { - ContentResolver resolver = context.getContentResolver(); - Cursor cur = resolver.query(uri, new String[] { DocumentsContract.Document.COLUMN_SIZE }, null, null, null); - if (cur != null) { - if (cur.moveToFirst()) - size = cur.getLong(0); - cur.close(); - } - return size; - } catch (IllegalArgumentException e) { - Log.e(QtTAG, "getSize(): Invalid Uri"); - e.printStackTrace(); - return size; - } catch (UnsupportedOperationException e) { - Log.e(QtTAG, "getSize(): Unsupported operation for given Uri"); - e.printStackTrace(); - return size; - } - } - - public static boolean checkFileExists(Context context, String contentUrl) - { - boolean exists = false; - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, "r"); - if (uri == null) { - Log.e(QtTAG, "checkFileExists(): No permissions to open Uri"); - return exists; - } else { - if (!m_cachedUris.containsKey(contentUrl)) - m_cachedUris.put(contentUrl, uri); - } - - try { - ContentResolver resolver = context.getContentResolver(); - Cursor cur = resolver.query(uri, null, null, null, null); - if (cur != null) { - exists = true; - cur.close(); - } - return exists; - } catch (IllegalArgumentException e) { - Log.e(QtTAG, "checkFileExists(): Invalid Uri"); - e.printStackTrace(); - return exists; - } catch (UnsupportedOperationException e) { - Log.e(QtTAG, "checkFileExists(): Unsupported operation for given Uri"); - e.printStackTrace(); - return false; - } - } - - public static boolean checkIfWritable(Context context, String contentUrl) - { - return getUriWithValidPermission(context, contentUrl, "w") != null; - } - - public static boolean checkIfDir(Context context, String contentUrl) - { - boolean isDir = false; - Uri uri = m_cachedUris.get(contentUrl); - if (m_knownDirs.contains(contentUrl)) - return true; - if (uri == null) { - uri = getUriWithValidPermission(context, contentUrl, "r"); - } - if (uri == null) { - Log.e(QtTAG, "isDir(): No permissions to open Uri"); - return isDir; - } else { - if (!m_cachedUris.containsKey(contentUrl)) - m_cachedUris.put(contentUrl, uri); - } - - try { - final List<String> paths = uri.getPathSegments(); - // getTreeDocumentId will throw an exception if it is not a directory so check manually - if (!paths.get(0).equals("tree")) - return false; - ContentResolver resolver = context.getContentResolver(); - Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, DocumentsContract.getTreeDocumentId(uri)); - if (!docUri.toString().startsWith(uri.toString())) - return false; - Cursor cur = resolver.query(docUri, new String[] { DocumentsContract.Document.COLUMN_MIME_TYPE }, null, null, null); - if (cur != null) { - if (cur.moveToFirst()) { - final String dirStr = new String(DocumentsContract.Document.MIME_TYPE_DIR); - isDir = cur.getString(0).equals(dirStr); - if (isDir) - m_knownDirs.add(contentUrl); - } - cur.close(); - } - return isDir; - } catch (IllegalArgumentException e) { - Log.e(QtTAG, "checkIfDir(): Invalid Uri"); - e.printStackTrace(); - return false; - } catch (UnsupportedOperationException e) { - Log.e(QtTAG, "checkIfDir(): Unsupported operation for given Uri"); - e.printStackTrace(); - return false; - } - } - public static String[] listContentsFromTreeUri(Context context, String contentUrl) - { - Uri treeUri = Uri.parse(contentUrl); - final ArrayList<String> results = new ArrayList<String>(); - if (treeUri == null) { - Log.e(QtTAG, "listContentsFromTreeUri(): Invalid uri"); - return results.toArray(new String[results.size()]); - } - final ContentResolver resolver = context.getContentResolver(); - final Uri docUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, - DocumentsContract.getTreeDocumentId(treeUri)); - final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(docUri, - DocumentsContract.getDocumentId(docUri)); - Cursor c = null; - final String dirStr = new String(DocumentsContract.Document.MIME_TYPE_DIR); - try { - c = resolver.query(childrenUri, new String[] { - DocumentsContract.Document.COLUMN_DOCUMENT_ID, DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE }, null, null, null); - while (c.moveToNext()) { - final String fileString = c.getString(1); - if (!m_cachedUris.containsKey(contentUrl + "/" + fileString)) { - m_cachedUris.put(contentUrl + "/" + fileString, - DocumentsContract.buildDocumentUriUsingTree(treeUri, c.getString(0))); - } - results.add(fileString); - if (c.getString(2).equals(dirStr)) - m_knownDirs.add(contentUrl + "/" + fileString); - } - c.close(); - } catch (Exception e) { - Log.w(QtTAG, "Failed query: " + e); - return results.toArray(new String[results.size()]); - } - return results.toArray(new String[results.size()]); - } // this method loads full path libs public static void loadQtLibraries(final ArrayList<String> libraries) { @@ -611,7 +436,8 @@ public class QtNative m_displayMetricsXDpi, m_displayMetricsYDpi, m_displayMetricsScaledDensity, - m_displayMetricsDensity); + m_displayMetricsDensity, + m_displayMetricsRefreshRate); } }); m_qtThread.post(new Runnable() { @@ -633,7 +459,8 @@ public class QtNative double XDpi, double YDpi, double scaledDensity, - double density) + double density, + float refreshRate) { /* Fix buggy dpi report */ if (XDpi < android.util.DisplayMetrics.DENSITY_LOW) @@ -643,14 +470,9 @@ public class QtNative synchronized (m_mainActivityMutex) { if (m_started) { - setDisplayMetrics(screenWidthPixels, - screenHeightPixels, - desktopWidthPixels, - desktopHeightPixels, - XDpi, - YDpi, - scaledDensity, - density); + setDisplayMetrics(screenWidthPixels, screenHeightPixels, desktopWidthPixels, + desktopHeightPixels, XDpi, YDpi, scaledDensity, density, + refreshRate); } else { m_displayMetricsScreenWidthPixels = screenWidthPixels; m_displayMetricsScreenHeightPixels = screenHeightPixels; @@ -660,6 +482,7 @@ public class QtNative m_displayMetricsYDpi = YDpi; m_displayMetricsScaledDensity = scaledDensity; m_displayMetricsDensity = density; + m_displayMetricsRefreshRate = refreshRate; } } } @@ -673,9 +496,10 @@ public class QtNative public static native void quitQtCoreApplication(); public static native void quitQtAndroidPlugin(); public static native void terminateQt(); + public static native boolean updateNativeActivity(); // application methods - private static void quitApp() + public static void quitApp() { runAction(new Runnable() { @Override @@ -685,6 +509,8 @@ public class QtNative m_activity.finish(); if (m_service != null) m_service.stopSelf(); + + m_started = false; } }); } @@ -707,9 +533,11 @@ public class QtNative } return 1; } - if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) { + if (action == MotionEvent.ACTION_DOWN + || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) { return 0; - } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) { + } else if (action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) { return 3; } return 2; @@ -761,6 +589,10 @@ public class QtNative touchEnd(id, 2); break; + case MotionEvent.ACTION_CANCEL: + touchCancel(id); + break; + default: touchEnd(id, 1); } @@ -860,6 +692,11 @@ public class QtNative }); } + private static int getSelectHandleWidth() + { + return m_activityDelegate.getSelectHandleWidth(); + } + private static void updateHandles(final int mode, final int editX, final int editY, @@ -878,25 +715,10 @@ public class QtNative }); } - private static void updateInputItemRectangle(final int x, - final int y, - final int w, - final int h) - { - runAction(new Runnable() { - @Override - public void run() { - m_activityDelegate.updateInputItemRectangle(x, y, w, h); - } - }); - } - - private static void showSoftwareKeyboard(final int x, final int y, final int width, final int height, - final int editorHeight, final int inputHints, final int enterKeyType) { @@ -904,7 +726,7 @@ public class QtNative @Override public void run() { if (m_activityDelegate != null) - m_activityDelegate.showSoftwareKeyboard(x, y, width, height, editorHeight, inputHints, enterKeyType); + m_activityDelegate.showSoftwareKeyboard(x, y, width, height, inputHints, enterKeyType); } }); } @@ -922,6 +744,7 @@ public class QtNative private static void hideSoftwareKeyboard() { + m_isKeyboardHiding = true; runAction(new Runnable() { @Override public void run() { @@ -944,25 +767,32 @@ public class QtNative }); } - private static void notifyAccessibilityLocationChange() + public static boolean isSoftwareKeyboardVisible() + { + if (m_activityDelegate == null) + return false; + return m_activityDelegate.isKeyboardVisible() && !m_isKeyboardHiding; + } + + private static void notifyAccessibilityLocationChange(final int viewId) { runAction(new Runnable() { @Override public void run() { if (m_activityDelegate != null) { - m_activityDelegate.notifyAccessibilityLocationChange(); + m_activityDelegate.notifyAccessibilityLocationChange(viewId); } } }); } - private static void notifyObjectHide(final int viewId) + private static void notifyObjectHide(final int viewId, final int parentId) { runAction(new Runnable() { @Override public void run() { if (m_activityDelegate != null) { - m_activityDelegate.notifyObjectHide(viewId); + m_activityDelegate.notifyObjectHide(viewId, parentId); } } }); @@ -980,6 +810,35 @@ public class QtNative }); } + private static void notifyValueChanged(final int viewId, final String value) + { + runAction(new Runnable() { + @Override + public void run() { + if (m_activityDelegate != null) { + m_activityDelegate.notifyValueChanged(viewId, value); + } + } + }); + } + + private static void notifyScrolledEvent(final int viewId) + { + runAction(new Runnable() { + @Override + public void run() { + if (m_activityDelegate != null) { + m_activityDelegate.notifyScrolledEvent(viewId); + } + } + }); + } + + public static void notifyQtAndroidPluginRunning(final boolean running) + { + m_activityDelegate.notifyQtAndroidPluginRunning(running); + } + private static void registerClipboardManager() { if (m_service == null || m_activity != null) { // Avoid freezing if only service @@ -1011,6 +870,7 @@ public class QtNative { if (Build.VERSION.SDK_INT >= 28 && m_clipboardManager != null) m_clipboardManager.clearPrimaryClip(); + m_usePrimaryClip = false; } private static void setClipboardText(String text) { @@ -1024,10 +884,8 @@ public class QtNative { try { if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { - ClipData primaryClip = m_clipboardManager.getPrimaryClip(); - for (int i = 0; i < primaryClip.getItemCount(); ++i) - if (primaryClip.getItemAt(i).getText() != null) - return true; + ClipDescription primaryClipDescription = m_clipboardManager.getPrimaryClipDescription(); + return primaryClipDescription.hasMimeType("text/*"); } } catch (Exception e) { Log.e(QtTAG, "Failed to get clipboard data", e); @@ -1082,10 +940,8 @@ public class QtNative { try { if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { - ClipData primaryClip = m_clipboardManager.getPrimaryClip(); - for (int i = 0; i < Objects.requireNonNull(primaryClip).getItemCount(); ++i) - if (primaryClip.getItemAt(i).getHtmlText() != null) - return true; + ClipDescription primaryClipDescription = m_clipboardManager.getPrimaryClipDescription(); + return primaryClipDescription.hasMimeType("text/html"); } } catch (Exception e) { Log.e(QtTAG, "Failed to get clipboard data", e); @@ -1121,10 +977,8 @@ public class QtNative { try { if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { - ClipData primaryClip = m_clipboardManager.getPrimaryClip(); - for (int i = 0; i < primaryClip.getItemCount(); ++i) - if (primaryClip.getItemAt(i).getUri() != null) - return true; + ClipDescription primaryClipDescription = m_clipboardManager.getPrimaryClipDescription(); + return primaryClipDescription.hasMimeType("text/uri-list"); } } catch (Exception e) { Log.e(QtTAG, "Failed to get clipboard data", e); @@ -1308,6 +1162,12 @@ public class QtNative }); } + public static void keyboardVisibilityUpdated(boolean visibility) + { + m_isKeyboardHiding = false; + keyboardVisibilityChanged(visibility); + } + private static String[] listAssetContent(android.content.res.AssetManager asset, String path) { String [] list; ArrayList<String> res = new ArrayList<String>(); @@ -1339,8 +1199,10 @@ public class QtNative double XDpi, double YDpi, double scaledDensity, - double density); + double density, + float refreshRate); public static native void handleOrientationChanged(int newRotation, int nativeOrientation); + public static native void handleRefreshRateChanged(float refreshRate); // screen methods // pointer methods @@ -1351,6 +1213,7 @@ public class QtNative public static native void touchBegin(int winId); 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); public static native void touchEnd(int winId, int action); + public static native void touchCancel(int winId); public static native void longPress(int winId, int x, int y); // pointer methods |