From e3689949ba5b23decb0ea85741a3f4829696788e Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Tue, 8 Dec 2015 12:43:03 +0200 Subject: Android: Remove support for API < 16 Starting with Qt 5.7 we removed support for API < 16 (Android v4.1) [ChangeLog][Android] Support for Android API < 16 was removed. Change-Id: I8bf396a9d70ab0996965e0c9f629800aa1fa6a45 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/android/accessibility/accessibility.pro | 2 - src/android/accessibility/jar/AndroidManifest.xml | 7 - src/android/accessibility/jar/bundledjar.pro | 3 - src/android/accessibility/jar/distributedjar.pro | 2 - src/android/accessibility/jar/jar.pri | 15 - src/android/accessibility/jar/jar.pro | 2 - .../accessibility/QtAccessibilityDelegate.java | 416 --------------------- .../accessibility/QtNativeAccessibility.java | 52 --- src/android/android.pro | 2 +- src/android/jar/jar.pri | 6 +- .../org/qtproject/qt5/android/ExtractStyle.java | 26 +- .../qtproject/qt5/android/QtActivityDelegate.java | 151 +++----- .../qt5/android/QtMessageDialogHelper.java | 81 ++-- .../src/org/qtproject/qt5/android/QtNative.java | 18 +- .../src/org/qtproject/qt5/android/QtPopupMenu.java | 66 ---- .../org/qtproject/qt5/android/QtPopupMenu14.java | 69 ---- .../src/org/qtproject/qt5/android/QtSurface.java | 3 - .../accessibility/QtAccessibilityDelegate.java | 416 +++++++++++++++++++++ .../accessibility/QtNativeAccessibility.java | 52 +++ src/android/java/res/values-ro/strings.xml | 1 + src/android/java/res/values/strings.xml | 1 + .../qtproject/qt5/android/bindings/QtActivity.java | 34 +- src/android/templates/AndroidManifest.xml | 2 +- 23 files changed, 587 insertions(+), 840 deletions(-) delete mode 100644 src/android/accessibility/accessibility.pro delete mode 100644 src/android/accessibility/jar/AndroidManifest.xml delete mode 100644 src/android/accessibility/jar/bundledjar.pro delete mode 100644 src/android/accessibility/jar/distributedjar.pro delete mode 100644 src/android/accessibility/jar/jar.pri delete mode 100644 src/android/accessibility/jar/jar.pro delete mode 100644 src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java delete mode 100644 src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java delete mode 100644 src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu.java delete mode 100644 src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu14.java create mode 100644 src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java create mode 100644 src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java (limited to 'src/android') diff --git a/src/android/accessibility/accessibility.pro b/src/android/accessibility/accessibility.pro deleted file mode 100644 index df5846945d..0000000000 --- a/src/android/accessibility/accessibility.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = jar diff --git a/src/android/accessibility/jar/AndroidManifest.xml b/src/android/accessibility/jar/AndroidManifest.xml deleted file mode 100644 index dc8343a55a..0000000000 --- a/src/android/accessibility/jar/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/src/android/accessibility/jar/bundledjar.pro b/src/android/accessibility/jar/bundledjar.pro deleted file mode 100644 index 85ba810310..0000000000 --- a/src/android/accessibility/jar/bundledjar.pro +++ /dev/null @@ -1,3 +0,0 @@ -TARGET = QtAndroidAccessibility-bundled -CONFIG += bundled_jar_file -include(jar.pri) diff --git a/src/android/accessibility/jar/distributedjar.pro b/src/android/accessibility/jar/distributedjar.pro deleted file mode 100644 index d161cf0cf6..0000000000 --- a/src/android/accessibility/jar/distributedjar.pro +++ /dev/null @@ -1,2 +0,0 @@ -TARGET = QtAndroidAccessibility -include(jar.pri) diff --git a/src/android/accessibility/jar/jar.pri b/src/android/accessibility/jar/jar.pri deleted file mode 100644 index 3ae9fed59d..0000000000 --- a/src/android/accessibility/jar/jar.pri +++ /dev/null @@ -1,15 +0,0 @@ -CONFIG += java -DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar -API_VERSION = android-16 - -PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/accessibility - -JAVACLASSPATH += $$PWD/src/ \ - $$DESTDIR/QtAndroid-bundled.jar -JAVASOURCES += \ - $$PATHPREFIX/QtAccessibilityDelegate.java \ - $$PATHPREFIX/QtNativeAccessibility.java - -# install -target.path = $$[QT_INSTALL_PREFIX]/jar -INSTALLS += target \ No newline at end of file diff --git a/src/android/accessibility/jar/jar.pro b/src/android/accessibility/jar/jar.pro deleted file mode 100644 index 8d19c1b7d6..0000000000 --- a/src/android/accessibility/jar/jar.pro +++ /dev/null @@ -1,2 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS += bundledjar.pro distributedjar.pro diff --git a/src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java b/src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java deleted file mode 100644 index 6f95675597..0000000000 --- a/src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java +++ /dev/null @@ -1,416 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Android port of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -package org.qtproject.qt5.android.accessibility; - -import android.accessibilityservice.AccessibilityService; -import android.app.Activity; -import android.graphics.Rect; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.text.TextUtils; - -import android.view.accessibility.*; -import android.view.MotionEvent; -import android.view.View.OnHoverListener; - -import android.content.Context; - -import java.util.LinkedList; -import java.util.List; - -import org.qtproject.qt5.android.QtActivityDelegate; - -public class QtAccessibilityDelegate extends View.AccessibilityDelegate -{ - private static final String TAG = "Qt A11Y"; - - // Qt uses the upper half of the unsiged integers - // all low positive ints should be fine. - public static final int INVALID_ID = 333; // half evil - - // The platform might ask for the class implementing the "view". - // Pretend to be an inner class of the QtSurface. - private static final String DEFAULT_CLASS_NAME = "$VirtualChild"; - - private View m_view = null; - private AccessibilityManager m_manager; - private QtActivityDelegate m_activityDelegate; - private Activity m_activity; - private ViewGroup m_layout; - - // The accessible object that currently has the "accessibility focus" - // usually indicated by a yellow rectangle on screen. - private int m_focusedVirtualViewId = INVALID_ID; - // When exploring the screen by touch, the item "hovered" by the finger. - private int m_hoveredVirtualViewId = INVALID_ID; - - // Cache coordinates of the view to know the global offset - // this is because the Android platform window does not take - // the offset of the view on screen into account (eg status bar on top) - private final int[] m_globalOffset = new int[2]; - - private class HoverEventListener implements View.OnHoverListener - { - @Override - public boolean onHover(View v, MotionEvent event) - { - return dispatchHoverEvent(event); - } - } - - public QtAccessibilityDelegate(Activity activity, ViewGroup layout, QtActivityDelegate activityDelegate) - { - m_activity = activity; - m_layout = layout; - m_activityDelegate = activityDelegate; - - m_manager = (AccessibilityManager) m_activity.getSystemService(Context.ACCESSIBILITY_SERVICE); - if (m_manager != null) { - AccessibilityManagerListener accServiceListener = new AccessibilityManagerListener(); - if (!m_manager.addAccessibilityStateChangeListener(accServiceListener)) - Log.w("Qt A11y", "Could not register a11y state change listener"); - if (m_manager.isEnabled()) - accServiceListener.onAccessibilityStateChanged(true); - } - } - - private class AccessibilityManagerListener implements AccessibilityManager.AccessibilityStateChangeListener - { - @Override - public void onAccessibilityStateChanged(boolean enabled) - { - if (enabled) { - try { - View view = m_view; - if (view == null) { - view = new View(m_activity); - view.setId(View.NO_ID); - } - - // ### Keep this for debugging for a while. It allows us to visually see that our View - // ### is on top of the surface(s) - // ColorDrawable color = new ColorDrawable(0x80ff8080); //0xAARRGGBB - // view.setBackground(color); - view.setAccessibilityDelegate(QtAccessibilityDelegate.this); - - // if all is fine, add it to the layout - if (m_view == null) { - //m_layout.addAccessibilityView(view); - m_layout.addView(view, m_activityDelegate.getSurfaceCount(), - new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - m_view = view; - - m_view.setOnHoverListener(new HoverEventListener()); - } catch (Exception e) { - // Unknown exception means something went wrong. - Log.w("Qt A11y", "Unknown exception: " + e.toString()); - } - } else { - if (m_view != null) { - m_layout.removeView(m_view); - m_view = null; - } - } - - QtNativeAccessibility.setActive(enabled); - } - } - - - @Override - public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) - { - return m_nodeProvider; - } - - // For "explore by touch" we need all movement events here first - // (user moves finger over screen to discover items on screen). - private boolean dispatchHoverEvent(MotionEvent event) - { - if (!m_manager.isTouchExplorationEnabled()) { - return false; - } - - int virtualViewId = QtNativeAccessibility.hitTest(event.getX(), event.getY()); - if (virtualViewId == INVALID_ID) { - virtualViewId = View.NO_ID; - } - - switch (event.getAction()) { - case MotionEvent.ACTION_HOVER_ENTER: - case MotionEvent.ACTION_HOVER_MOVE: - setHoveredVirtualViewId(virtualViewId); - break; - case MotionEvent.ACTION_HOVER_EXIT: - setHoveredVirtualViewId(virtualViewId); - break; - } - - return true; - } - - public boolean sendEventForVirtualViewId(int virtualViewId, int eventType) - { - if ((virtualViewId == INVALID_ID) || !m_manager.isEnabled()) { - Log.w(TAG, "sendEventForVirtualViewId for invalid view"); - return false; - } - - final ViewGroup group = (ViewGroup) m_view.getParent(); - if (group == null) { - Log.w(TAG, "Could not send AccessibilityEvent because group was null. This should really not happen."); - return false; - } - - final AccessibilityEvent event; - event = getEventForVirtualViewId(virtualViewId, eventType); - return group.requestSendAccessibilityEvent(m_view, event); - } - - public void invalidateVirtualViewId(int virtualViewId) - { - sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - } - - private void setHoveredVirtualViewId(int virtualViewId) - { - if (m_hoveredVirtualViewId == virtualViewId) { - return; - } - - final int previousVirtualViewId = m_hoveredVirtualViewId; - m_hoveredVirtualViewId = virtualViewId; - sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); - sendEventForVirtualViewId(previousVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); - } - - private AccessibilityEvent getEventForVirtualViewId(int virtualViewId, int eventType) - { - final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); - - event.setEnabled(true); - event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); - - event.setContentDescription(QtNativeAccessibility.descriptionForAccessibleObject(virtualViewId)); - if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) - Log.w(TAG, "AccessibilityEvent with empty description"); - - event.setPackageName(m_view.getContext().getPackageName()); - event.setSource(m_view, virtualViewId); - return event; - } - - private void dumpNodes(int parentId) - { - Log.i(TAG, "A11Y hierarchy: " + parentId + " parent: " + QtNativeAccessibility.parentId(parentId)); - Log.i(TAG, " desc: " + QtNativeAccessibility.descriptionForAccessibleObject(parentId) + " rect: " + QtNativeAccessibility.screenRect(parentId)); - Log.i(TAG, " NODE: " + getNodeForVirtualViewId(parentId)); - int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(parentId); - for (int i = 0; i < ids.length; ++i) { - Log.i(TAG, parentId + " has child: " + ids[i]); - dumpNodes(ids[i]); - } - } - - private AccessibilityNodeInfo getNodeForView() - { - // Since we don't want the parent to be focusable, but we can't remove - // actions from a node, copy over the necessary fields. - final AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(m_view); - final AccessibilityNodeInfo source = AccessibilityNodeInfo.obtain(m_view); - m_view.onInitializeAccessibilityNodeInfo(source); - - // Get the actual position on screen, taking the status bar into account. - m_view.getLocationOnScreen(m_globalOffset); - final int offsetX = m_globalOffset[0]; - final int offsetY = m_globalOffset[1]; - - // Copy over parent and screen bounds. - final Rect m_tempParentRect = new Rect(); - source.getBoundsInParent(m_tempParentRect); - result.setBoundsInParent(m_tempParentRect); - - final Rect m_tempScreenRect = new Rect(); - source.getBoundsInScreen(m_tempScreenRect); - m_tempScreenRect.offset(offsetX, offsetY); - result.setBoundsInScreen(m_tempScreenRect); - - // Set up the parent view, if applicable. - final ViewParent parent = m_view.getParent(); - if (parent instanceof View) { - result.setParent((View) parent); - } - - result.setVisibleToUser(source.isVisibleToUser()); - result.setPackageName(source.getPackageName()); - result.setClassName(source.getClassName()); - -// Spit out the entire hierarchy for debugging purposes -// dumpNodes(-1); - - int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(-1); - for (int i = 0; i < ids.length; ++i) - result.addChild(m_view, ids[i]); - - return result; - } - - private AccessibilityNodeInfo getNodeForVirtualViewId(int virtualViewId) - { - final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(); - - node.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); - node.setPackageName(m_view.getContext().getPackageName()); - - if (!QtNativeAccessibility.populateNode(virtualViewId, node)) - return node; - - // set only if valid, otherwise we return a node that is invalid and will crash when accessed - node.setSource(m_view, virtualViewId); - - if (TextUtils.isEmpty(node.getText()) && TextUtils.isEmpty(node.getContentDescription())) - Log.w(TAG, "AccessibilityNodeInfo with empty contentDescription: " + virtualViewId); - - int parentId = QtNativeAccessibility.parentId(virtualViewId); - node.setParent(m_view, parentId); - - Rect screenRect = QtNativeAccessibility.screenRect(virtualViewId); - final int offsetX = m_globalOffset[0]; - final int offsetY = m_globalOffset[1]; - screenRect.offset(offsetX, offsetY); - node.setBoundsInScreen(screenRect); - - Rect rectInParent = screenRect; - Rect parentScreenRect = QtNativeAccessibility.screenRect(parentId); - rectInParent.offset(-parentScreenRect.left, -parentScreenRect.top); - node.setBoundsInParent(rectInParent); - - // Manage internal accessibility focus state. - if (m_focusedVirtualViewId == virtualViewId) { - node.setAccessibilityFocused(true); - node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); - } else { - node.setAccessibilityFocused(false); - node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); - } - - int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(virtualViewId); - for (int i = 0; i < ids.length; ++i) - node.addChild(m_view, ids[i]); - return node; - } - - private AccessibilityNodeProvider m_nodeProvider = new AccessibilityNodeProvider() - { - @Override - public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) - { - if (virtualViewId == View.NO_ID) { - return getNodeForView(); - } - return getNodeForVirtualViewId(virtualViewId); - } - - @Override - public boolean performAction(int virtualViewId, int action, Bundle arguments) - { - boolean handled = false; - //Log.i(TAG, "PERFORM ACTION: " + action + " on " + virtualViewId); - switch (action) { - case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: - // Only handle the FOCUS action if it's placing focus on - // a different view that was previously focused. - if (m_focusedVirtualViewId != virtualViewId) { - m_focusedVirtualViewId = virtualViewId; - m_view.invalidate(); - sendEventForVirtualViewId(virtualViewId, - AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); - handled = true; - } - break; - case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: - if (m_focusedVirtualViewId == virtualViewId) { - m_focusedVirtualViewId = INVALID_ID; - } - // Since we're managing focus at the parent level, we are - // likely to receive a FOCUS action before a CLEAR_FOCUS - // action. We'll give the benefit of the doubt to the - // framework and always handle FOCUS_CLEARED. - m_view.invalidate(); - sendEventForVirtualViewId(virtualViewId, - AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); - handled = true; - break; - default: - // Let the node provider handle focus for the view node. - if (virtualViewId == View.NO_ID) { - return m_view.performAccessibilityAction(action, arguments); - } - } - handled |= performActionForVirtualViewId(virtualViewId, action, arguments); - - return handled; - } - }; - - protected boolean performActionForVirtualViewId(int virtualViewId, int action, Bundle arguments) - { -// Log.i(TAG, "ACTION " + action + " on " + virtualViewId); -// dumpNodes(virtualViewId); - boolean success = false; - switch (action) { - case AccessibilityNodeInfo.ACTION_CLICK: - success = QtNativeAccessibility.clickAction(virtualViewId); - if (success) - sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); - break; - case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: - success = QtNativeAccessibility.scrollForward(virtualViewId); - if (success) - sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_SCROLLED); - break; - case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: - success = QtNativeAccessibility.scrollBackward(virtualViewId); - if (success) - sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_SCROLLED); - break; - } - return success; - } -} diff --git a/src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java b/src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java deleted file mode 100644 index bfda2d55b7..0000000000 --- a/src/android/accessibility/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Android port of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -package org.qtproject.qt5.android.accessibility; - -import android.graphics.Rect; -import android.view.accessibility.AccessibilityNodeInfo; - -class QtNativeAccessibility -{ - static native void setActive(boolean enable); - static native int[] childIdListForAccessibleObject(int objectId); - static native int parentId(int objectId); - static native String descriptionForAccessibleObject(int objectId); - static native Rect screenRect(int objectId); - static native int hitTest(float x, float y); - static native boolean clickAction(int objectId); - static native boolean scrollForward(int objectId); - static native boolean scrollBackward(int objectId); - - static native boolean populateNode(int objectId, AccessibilityNodeInfo node); -} diff --git a/src/android/android.pro b/src/android/android.pro index b17dd15cd4..1174084591 100644 --- a/src/android/android.pro +++ b/src/android/android.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs CONFIG += ordered -SUBDIRS = jar java templates accessibility +SUBDIRS = jar java templates diff --git a/src/android/jar/jar.pri b/src/android/jar/jar.pri index a962af18ab..b45b353f95 100644 --- a/src/android/jar/jar.pri +++ b/src/android/jar/jar.pri @@ -6,6 +6,8 @@ PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/ JAVACLASSPATH += $$PWD/src/ JAVASOURCES += \ + $$PATHPREFIX/accessibility/QtAccessibilityDelegate.java \ + $$PATHPREFIX/accessibility/QtNativeAccessibility.java \ $$PATHPREFIX/QtActivityDelegate.java \ $$PATHPREFIX/QtEditText.java \ $$PATHPREFIX/QtInputConnection.java \ @@ -14,9 +16,7 @@ JAVASOURCES += \ $$PATHPREFIX/QtNative.java \ $$PATHPREFIX/QtNativeLibrariesDir.java \ $$PATHPREFIX/QtSurface.java \ - $$PATHPREFIX/ExtractStyle.java \ - $$PATHPREFIX/QtPopupMenu.java \ - $$PATHPREFIX/QtPopupMenu14.java + $$PATHPREFIX/ExtractStyle.java # install target.path = $$[QT_INSTALL_PREFIX]/jar diff --git a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java index f5dac1fa60..9d0031d0de 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java @@ -1813,11 +1813,7 @@ public class ExtractStyle { jsonWriter.name("simple_spinner_item").value(extractItemStyle(android.R.layout.simple_spinner_item, "simple_spinner_item", -1)); jsonWriter.name("simple_spinner_dropdown_item").value(extractItemStyle(android.R.layout.simple_spinner_dropdown_item, "simple_spinner_dropdown_item",android.R.style.TextAppearance_Large)); jsonWriter.name("simple_dropdown_item_1line").value(extractItemStyle(android.R.layout.simple_dropdown_item_1line, "simple_dropdown_item_1line",android.R.style.TextAppearance_Large)); - if (Build.VERSION.SDK_INT > 10) { - Class layoutClass = Class.forName("android.R$layout"); - int styleId = layoutClass.getDeclaredField("simple_selectable_list_item").getInt(null); - jsonWriter.name("simple_selectable_list_item").value(extractItemStyle(styleId, "simple_selectable_list_item",android.R.style.TextAppearance_Large)); - } + jsonWriter.name("simple_selectable_list_item").value(extractItemStyle(android.R.layout.simple_selectable_list_item, "simple_selectable_list_item",android.R.style.TextAppearance_Large)); } catch (Exception e) { e.printStackTrace(); } @@ -2018,9 +2014,7 @@ public class ExtractStyle { extractProgressBar(jsonWriter, "progressBarStyleSmall", null); extractProgressBar(jsonWriter, "progressBarStyle", null); extractAbsSeekBar(jsonWriter, "seekBarStyle", "QSlider"); - if (Build.VERSION.SDK_INT > 13) { - extractSwitch(jsonWriter, "switchStyle", null); - } + extractSwitch(jsonWriter, "switchStyle", null); extractCompoundButton(jsonWriter, "checkboxStyle", "QCheckBox"); jsonWriter.name("editTextStyle").value(extractTextAppearanceInformations("editTextStyle", "QLineEdit", null, -1)); extractCompoundButton(jsonWriter, "radioButtonStyle", "QRadioButton"); @@ -2030,15 +2024,13 @@ public class ExtractStyle { jsonWriter.name("listSeparatorTextViewStyle").value(extractTextAppearanceInformations("listSeparatorTextViewStyle", null, null, -1)); extractItemsStyle(jsonWriter); extractCompoundButton(jsonWriter, "buttonStyleToggle", null); - if (Build.VERSION.SDK_INT > 10) { - extractCalendar(jsonWriter, "calendarViewStyle", "QCalendarWidget"); - extractToolBar(jsonWriter, "actionBarStyle", "QToolBar"); - jsonWriter.name("actionButtonStyle").value(extractTextAppearanceInformations("actionButtonStyle", "QToolButton", null, -1)); - jsonWriter.name("actionBarTabTextStyle").value(extractTextAppearanceInformations("actionBarTabTextStyle", null, null, -1)); - jsonWriter.name("actionBarTabStyle").value(extractTextAppearanceInformations("actionBarTabStyle", null, null, -1)); - jsonWriter.name("actionOverflowButtonStyle").value(extractImageViewInformations("actionOverflowButtonStyle", null)); - extractTabBar(jsonWriter, "actionBarTabBarStyle", "QTabBar"); - } + extractCalendar(jsonWriter, "calendarViewStyle", "QCalendarWidget"); + extractToolBar(jsonWriter, "actionBarStyle", "QToolBar"); + jsonWriter.name("actionButtonStyle").value(extractTextAppearanceInformations("actionButtonStyle", "QToolButton", null, -1)); + jsonWriter.name("actionBarTabTextStyle").value(extractTextAppearanceInformations("actionBarTabTextStyle", null, null, -1)); + jsonWriter.name("actionBarTabStyle").value(extractTextAppearanceInformations("actionBarTabStyle", null, null, -1)); + jsonWriter.name("actionOverflowButtonStyle").value(extractImageViewInformations("actionOverflowButtonStyle", null)); + extractTabBar(jsonWriter, "actionBarTabBarStyle", "QTabBar"); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 0a9e75c73d..f75b6562af 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -67,6 +67,7 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.view.ViewTreeObserver; +import android.widget.PopupMenu; import android.graphics.Rect; import java.io.BufferedReader; @@ -80,6 +81,8 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; +import org.qtproject.qt5.android.accessibility.QtAccessibilityDelegate; + public class QtActivityDelegate { private Activity m_activity = null; @@ -135,35 +138,23 @@ public class QtActivityDelegate m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); try { - if (Build.VERSION.SDK_INT >= 14) { - int flags = View.class.getDeclaredField("SYSTEM_UI_FLAG_HIDE_NAVIGATION").getInt(null); - if (Build.VERSION.SDK_INT >= 16) { - flags |= View.class.getDeclaredField("SYSTEM_UI_FLAG_LAYOUT_STABLE").getInt(null); - flags |= View.class.getDeclaredField("SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION").getInt(null); - flags |= View.class.getDeclaredField("SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN").getInt(null); - flags |= View.class.getDeclaredField("SYSTEM_UI_FLAG_FULLSCREEN").getInt(null); - - if (Build.VERSION.SDK_INT >= 19) - flags |= View.class.getDeclaredField("SYSTEM_UI_FLAG_IMMERSIVE_STICKY").getInt(null); - } - Method m = View.class.getMethod("setSystemUiVisibility", int.class); - m.invoke(m_activity.getWindow().getDecorView(), flags | View.INVISIBLE); - } + int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; + flags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE; + flags |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; + flags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + flags |= View.SYSTEM_UI_FLAG_FULLSCREEN; + + if (Build.VERSION.SDK_INT >= 19) + flags |= View.class.getDeclaredField("SYSTEM_UI_FLAG_IMMERSIVE_STICKY").getInt(null); + + m_activity.getWindow().getDecorView().setSystemUiVisibility(flags | View.INVISIBLE); } catch (Exception e) { e.printStackTrace(); } } else { m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); - if (Build.VERSION.SDK_INT >= 14) { - try { - int ui_flag_visible = View.class.getDeclaredField("SYSTEM_UI_FLAG_VISIBLE").getInt(null); - Method m = View.class.getMethod("setSystemUiVisibility", int.class); - m.invoke(m_activity.getWindow().getDecorView(), ui_flag_visible); - } catch (Exception e) { - e.printStackTrace(); - } - } + m_activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); } m_layout.requestLayout(); } @@ -286,8 +277,7 @@ public class QtActivityDelegate imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT; break; case EnterKeyPrevious: - if (Build.VERSION.SDK_INT > 10) - imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS; + imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_PREVIOUS; break; } @@ -300,7 +290,7 @@ public class QtActivityDelegate | android.text.InputType.TYPE_NUMBER_FLAG_SIGNED); } - if (Build.VERSION.SDK_INT > 10 && (inputHints & ImhHiddenText) != 0) + if ((inputHints & ImhHiddenText) != 0) inputType |= 0x10 /* TYPE_NUMBER_VARIATION_PASSWORD */; } else if ((inputHints & ImhDialableCharactersOnly) != 0) { inputType = android.text.InputType.TYPE_CLASS_PHONE; @@ -478,13 +468,7 @@ public class QtActivityDelegate m_super_onKeyUp = m_activity.getClass().getMethod("super_onKeyUp", Integer.TYPE, KeyEvent.class); m_super_onConfigurationChanged = m_activity.getClass().getMethod("super_onConfigurationChanged", Configuration.class); m_super_onActivityResult = m_activity.getClass().getMethod("super_onActivityResult", Integer.TYPE, Integer.TYPE, Intent.class); - if (Build.VERSION.SDK_INT >= 12) { - try { - m_super_dispatchGenericMotionEvent = m_activity.getClass().getMethod("super_dispatchGenericMotionEvent", MotionEvent.class); - } catch (Exception e) { - } - } - + m_super_dispatchGenericMotionEvent = m_activity.getClass().getMethod("super_dispatchGenericMotionEvent", MotionEvent.class); } catch (Exception e) { e.printStackTrace(); return false; @@ -500,10 +484,8 @@ public class QtActivityDelegate + "\tNECESSITAS_API_LEVEL=" + necessitasApiLevel + "\tHOME=" + m_activity.getFilesDir().getAbsolutePath() + "\tTMPDIR=" + m_activity.getFilesDir().getAbsolutePath(); - if (Build.VERSION.SDK_INT < 14) - additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Droid Sans;Droid Sans Fallback"; - else - additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Roboto;Droid Sans;Droid Sans Fallback"; + + additionalEnvironmentVariables += "\tQT_ANDROID_FONTS=Roboto;Droid Sans;Droid Sans Fallback"; additionalEnvironmentVariables += getAppIconSize(activity); @@ -884,21 +866,7 @@ public class QtActivityDelegate public void initializeAccessibility() { - // Initialize accessibility - try { - final String a11yDelegateClassName = "org.qtproject.qt5.android.accessibility.QtAccessibilityDelegate"; - Class qtDelegateClass = Class.forName(a11yDelegateClassName); - Constructor constructor = qtDelegateClass.getConstructor(android.app.Activity.class, - android.view.ViewGroup.class, - this.getClass()); - Object accessibilityDelegate = constructor.newInstance(m_activity, m_layout, this); - } catch (ClassNotFoundException e) { - // Class not found is fine since we are compatible with Android API < 16, but the function will - // only be available with that API level. - } catch (Exception e) { - // Unknown exception means something went wrong. - Log.w("Qt A11y", "Unknown exception: " + e.toString()); - } + new QtAccessibilityDelegate(m_activity, m_layout, this); } public void onConfigurationChanged(Configuration configuration) @@ -1118,17 +1086,9 @@ public class QtActivityDelegate public void resetOptionsMenu() { - if (Build.VERSION.SDK_INT > 10) { - try { - Activity.class.getMethod("invalidateOptionsMenu").invoke(m_activity); - } catch (Exception e) { - e.printStackTrace(); - } - } - else - if (m_optionsMenuIsVisible) - m_activity.closeOptionsMenu(); + m_activity.invalidateOptionsMenu(); } + private boolean m_contextMenuVisible = false; public void onCreateContextMenu(ContextMenu menu, View v, @@ -1164,15 +1124,22 @@ public class QtActivityDelegate m_layout.postDelayed(new Runnable() { @Override public void run() { - if (Build.VERSION.SDK_INT < 11 || w <= 0 || h <= 0) { - m_activity.openContextMenu(m_layout); - } else if (Build.VERSION.SDK_INT < 14) { - m_layout.setLayoutParams(m_editText, new QtLayout.LayoutParams(w, h, x, y), false); - QtPopupMenu.getInstance().showMenu(m_editText); - } else { - m_layout.setLayoutParams(m_editText, new QtLayout.LayoutParams(w, h, x, y), false); - QtPopupMenu14.getInstance().showMenu(m_editText); - } + m_layout.setLayoutParams(m_editText, new QtLayout.LayoutParams(w, h, x, y), false); + PopupMenu popup = new PopupMenu(m_activity, m_editText); + QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu()); + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + return QtActivityDelegate.this.onContextItemSelected(menuItem); + } + }); + popup.setOnDismissListener(new PopupMenu.OnDismissListener() { + @Override + public void onDismiss(PopupMenu popupMenu) { + QtActivityDelegate.this.onContextMenuClosed(popupMenu.getMenu()); + } + }); + popup.show(); } }, 100); } @@ -1182,46 +1149,12 @@ public class QtActivityDelegate m_activity.closeContextMenu(); } - private boolean hasPermanentMenuKey() - { - try { - return Build.VERSION.SDK_INT < 11 || (Build.VERSION.SDK_INT >= 14 && - (Boolean)ViewConfiguration.class.getMethod("hasPermanentMenuKey").invoke(ViewConfiguration.get(m_activity))); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - private Object getActionBar() - { - try { - return Activity.class.getMethod("getActionBar").invoke(m_activity); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - private void setActionBarVisibility(boolean visible) { - if (hasPermanentMenuKey() || !visible) { - if (Build.VERSION.SDK_INT > 10 && getActionBar() != null) { - try { - Class.forName("android.app.ActionBar").getMethod("hide").invoke(getActionBar()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - } else { - if (Build.VERSION.SDK_INT > 10 && getActionBar() != null) - try { - Class.forName("android.app.ActionBar").getMethod("show").invoke(getActionBar()); - } catch (Exception e) { - e.printStackTrace(); - } - } + if (ViewConfiguration.get(m_activity).hasPermanentMenuKey() || !visible) + m_activity.getActionBar().hide(); + else + m_activity.getActionBar().show(); } public void insertNativeView(int id, View view, int x, int y, int w, int h) { diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java b/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java index 341bc159c8..c0ebf3980f 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java @@ -100,14 +100,12 @@ public class QtMessageDialogHelper if (m_icon == 0) return null; - if (Build.VERSION.SDK_INT > 10) { - try { - TypedValue typedValue = new TypedValue(); - m_theme.resolveAttribute(Class.forName("android.R$attr").getDeclaredField("alertDialogIcon").getInt(null), typedValue, true); - return m_activity.getResources().getDrawable(typedValue.resourceId); - } catch (Exception e) { - e.printStackTrace(); - } + try { + TypedValue typedValue = new TypedValue(); + m_theme.resolveAttribute(android.R.attr.alertDialogIcon, typedValue, true); + return m_activity.getResources().getDrawable(typedValue.resourceId); + } catch (Exception e) { + e.printStackTrace(); } // Information, Warning, Critical, Question @@ -115,7 +113,7 @@ public class QtMessageDialogHelper { case 1: // Information try { - return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_dialog_info").getInt(null)); + return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_info); } catch (Exception e) { e.printStackTrace(); } @@ -129,14 +127,14 @@ public class QtMessageDialogHelper // break; case 3: // Critical try { - return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_dialog_alert").getInt(null)); + return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert); } catch (Exception e) { e.printStackTrace(); } break; case 4: // Question try { - return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_menu_help").getInt(null)); + return m_activity.getResources().getDrawable(android.R.drawable.ic_menu_help); } catch (Exception e) { e.printStackTrace(); } @@ -310,15 +308,11 @@ public class QtMessageDialogHelper for (ButtonStruct button: m_buttonsList) { Button bv; - if (Build.VERSION.SDK_INT > 10) { - try { - bv = new Button(m_activity, null, Class.forName("android.R$attr").getDeclaredField("borderlessButtonStyle").getInt(null)); - } catch (Exception e) { - bv = new Button(m_activity); - e.printStackTrace(); - } - } else { + try { + bv = new Button(m_activity, null, Class.forName("android.R$attr").getDeclaredField("borderlessButtonStyle").getInt(null)); + } catch (Exception e) { bv = new Button(m_activity); + e.printStackTrace(); } bv.setText(button.m_text); @@ -327,14 +321,12 @@ public class QtMessageDialogHelper { LinearLayout.LayoutParams layout = null; View spacer = new View(m_activity); - if (Build.VERSION.SDK_INT > 10) { - try { - layout = new LinearLayout.LayoutParams(1, RelativeLayout.LayoutParams.MATCH_PARENT); - spacer.setBackgroundDrawable(getStyledDrawable("dividerVertical")); - buttonsLayout.addView(spacer, layout); - } catch (Exception e) { - e.printStackTrace(); - } + try { + layout = new LinearLayout.LayoutParams(1, RelativeLayout.LayoutParams.MATCH_PARENT); + spacer.setBackgroundDrawable(getStyledDrawable("dividerVertical")); + buttonsLayout.addView(spacer, layout); + } catch (Exception e) { + e.printStackTrace(); } } LinearLayout.LayoutParams layout = null; @@ -343,23 +335,21 @@ public class QtMessageDialogHelper firstButton = false; } - if (Build.VERSION.SDK_INT > 10) { - try { - View horizontalDevider = new View(m_activity); - horizontalDevider.setId(id++); - horizontalDevider.setBackgroundDrawable(getStyledDrawable("dividerHorizontal")); - RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 1); - relativeParams.setMargins(0, 10, 0, 0); - if (lastView != null) { - relativeParams.addRule(RelativeLayout.BELOW, lastView.getId()); - } - else - relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); - dialogLayout.addView(horizontalDevider, relativeParams); - lastView = horizontalDevider; - } catch (Exception e) { - e.printStackTrace(); + try { + View horizontalDevider = new View(m_activity); + horizontalDevider.setId(id++); + horizontalDevider.setBackgroundDrawable(getStyledDrawable("dividerHorizontal")); + RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 1); + relativeParams.setMargins(0, 10, 0, 0); + if (lastView != null) { + relativeParams.addRule(RelativeLayout.BELOW, lastView.getId()); } + else + relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); + dialogLayout.addView(horizontalDevider, relativeParams); + lastView = horizontalDevider; + } catch (Exception e) { + e.printStackTrace(); } RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); if (lastView != null) { @@ -367,10 +357,7 @@ public class QtMessageDialogHelper } else relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); - if (Build.VERSION.SDK_INT < 11) - relativeParams.setMargins(2, 12, 2, 4); - else - relativeParams.setMargins(2, 0, 2, 0); + relativeParams.setMargins(2, 0, 2, 0); dialogLayout.addView(buttonsLayout, relativeParams); } scrollView.addView(dialogLayout); 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 8880c003e7..804347e080 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -328,16 +328,14 @@ public class QtNative { int pointerType = 0; - if (Build.VERSION.SDK_INT >= 14) { - switch (event.getToolType(0)) { - case MotionEvent.TOOL_TYPE_STYLUS: - pointerType = 1; // QTabletEvent::Pen - break; - case MotionEvent.TOOL_TYPE_ERASER: - pointerType = 3; // QTabletEvent::Eraser - break; - // TODO TOOL_TYPE_MOUSE - } + switch (event.getToolType(0)) { + case MotionEvent.TOOL_TYPE_STYLUS: + pointerType = 1; // QTabletEvent::Pen + break; + case MotionEvent.TOOL_TYPE_ERASER: + pointerType = 3; // QTabletEvent::Eraser + break; + // TODO TOOL_TYPE_MOUSE } if (pointerType != 0) { diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu.java b/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu.java deleted file mode 100644 index d89b454b77..0000000000 --- a/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu.java +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 BogDan Vatra -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Android port of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -package org.qtproject.qt5.android; - -import android.view.MenuItem; -import android.view.View; -import android.widget.PopupMenu; - -public class QtPopupMenu { - private QtPopupMenu() { } - - private static class QtPopupMenuHolder { - private static final QtPopupMenu INSTANCE = new QtPopupMenu(); - } - - public static QtPopupMenu getInstance() { - return QtPopupMenuHolder.INSTANCE; - } - - public void showMenu(View anchor) - { - PopupMenu popup = new PopupMenu(QtNative.activity(), anchor); - QtNative.activityDelegate().onCreatePopupMenu(popup.getMenu()); - popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem menuItem) { - boolean res = QtNative.onContextItemSelected(menuItem.getItemId(), menuItem.isChecked()); - if (res) - QtNative.activityDelegate().onContextMenuClosed(null); - return res; - } - }); - popup.show(); - } -} diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu14.java b/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu14.java deleted file mode 100644 index edef682dec..0000000000 --- a/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu14.java +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 BogDan Vatra -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Android port of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -package org.qtproject.qt5.android; - -import android.view.MenuItem; -import android.view.View; -import android.widget.PopupMenu; - -public class QtPopupMenu14 { - private QtPopupMenu14() { } - - private static class QtPopupMenu14Holder { - private static final QtPopupMenu14 INSTANCE = new QtPopupMenu14(); - } - - public static QtPopupMenu14 getInstance() { - return QtPopupMenu14Holder.INSTANCE; - } - - public void showMenu(View anchor) - { - PopupMenu popup = new PopupMenu(QtNative.activity(), anchor); - QtNative.activityDelegate().onCreatePopupMenu(popup.getMenu()); - popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem menuItem) { - return QtNative.activityDelegate().onContextItemSelected(menuItem); - } - }); - popup.setOnDismissListener(new PopupMenu.OnDismissListener() { - @Override - public void onDismiss(PopupMenu popupMenu) { - QtNative.activityDelegate().onContextMenuClosed(popupMenu.getMenu()); - } - }); - popup.show(); - } -} diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java index 74433d2b65..51d0410816 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java @@ -62,9 +62,6 @@ public class QtSurface extends SurfaceView implements SurfaceHolder.Callback else getHolder().setFormat(PixelFormat.RGBA_8888); - if (android.os.Build.VERSION.SDK_INT < 11) - getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU); - setId(id); m_gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { diff --git a/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java new file mode 100644 index 0000000000..6f95675597 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java @@ -0,0 +1,416 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Android port of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +package org.qtproject.qt5.android.accessibility; + +import android.accessibilityservice.AccessibilityService; +import android.app.Activity; +import android.graphics.Rect; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.text.TextUtils; + +import android.view.accessibility.*; +import android.view.MotionEvent; +import android.view.View.OnHoverListener; + +import android.content.Context; + +import java.util.LinkedList; +import java.util.List; + +import org.qtproject.qt5.android.QtActivityDelegate; + +public class QtAccessibilityDelegate extends View.AccessibilityDelegate +{ + private static final String TAG = "Qt A11Y"; + + // Qt uses the upper half of the unsiged integers + // all low positive ints should be fine. + public static final int INVALID_ID = 333; // half evil + + // The platform might ask for the class implementing the "view". + // Pretend to be an inner class of the QtSurface. + private static final String DEFAULT_CLASS_NAME = "$VirtualChild"; + + private View m_view = null; + private AccessibilityManager m_manager; + private QtActivityDelegate m_activityDelegate; + private Activity m_activity; + private ViewGroup m_layout; + + // The accessible object that currently has the "accessibility focus" + // usually indicated by a yellow rectangle on screen. + private int m_focusedVirtualViewId = INVALID_ID; + // When exploring the screen by touch, the item "hovered" by the finger. + private int m_hoveredVirtualViewId = INVALID_ID; + + // Cache coordinates of the view to know the global offset + // this is because the Android platform window does not take + // the offset of the view on screen into account (eg status bar on top) + private final int[] m_globalOffset = new int[2]; + + private class HoverEventListener implements View.OnHoverListener + { + @Override + public boolean onHover(View v, MotionEvent event) + { + return dispatchHoverEvent(event); + } + } + + public QtAccessibilityDelegate(Activity activity, ViewGroup layout, QtActivityDelegate activityDelegate) + { + m_activity = activity; + m_layout = layout; + m_activityDelegate = activityDelegate; + + m_manager = (AccessibilityManager) m_activity.getSystemService(Context.ACCESSIBILITY_SERVICE); + if (m_manager != null) { + AccessibilityManagerListener accServiceListener = new AccessibilityManagerListener(); + if (!m_manager.addAccessibilityStateChangeListener(accServiceListener)) + Log.w("Qt A11y", "Could not register a11y state change listener"); + if (m_manager.isEnabled()) + accServiceListener.onAccessibilityStateChanged(true); + } + } + + private class AccessibilityManagerListener implements AccessibilityManager.AccessibilityStateChangeListener + { + @Override + public void onAccessibilityStateChanged(boolean enabled) + { + if (enabled) { + try { + View view = m_view; + if (view == null) { + view = new View(m_activity); + view.setId(View.NO_ID); + } + + // ### Keep this for debugging for a while. It allows us to visually see that our View + // ### is on top of the surface(s) + // ColorDrawable color = new ColorDrawable(0x80ff8080); //0xAARRGGBB + // view.setBackground(color); + view.setAccessibilityDelegate(QtAccessibilityDelegate.this); + + // if all is fine, add it to the layout + if (m_view == null) { + //m_layout.addAccessibilityView(view); + m_layout.addView(view, m_activityDelegate.getSurfaceCount(), + new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + m_view = view; + + m_view.setOnHoverListener(new HoverEventListener()); + } catch (Exception e) { + // Unknown exception means something went wrong. + Log.w("Qt A11y", "Unknown exception: " + e.toString()); + } + } else { + if (m_view != null) { + m_layout.removeView(m_view); + m_view = null; + } + } + + QtNativeAccessibility.setActive(enabled); + } + } + + + @Override + public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) + { + return m_nodeProvider; + } + + // For "explore by touch" we need all movement events here first + // (user moves finger over screen to discover items on screen). + private boolean dispatchHoverEvent(MotionEvent event) + { + if (!m_manager.isTouchExplorationEnabled()) { + return false; + } + + int virtualViewId = QtNativeAccessibility.hitTest(event.getX(), event.getY()); + if (virtualViewId == INVALID_ID) { + virtualViewId = View.NO_ID; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_HOVER_ENTER: + case MotionEvent.ACTION_HOVER_MOVE: + setHoveredVirtualViewId(virtualViewId); + break; + case MotionEvent.ACTION_HOVER_EXIT: + setHoveredVirtualViewId(virtualViewId); + break; + } + + return true; + } + + public boolean sendEventForVirtualViewId(int virtualViewId, int eventType) + { + if ((virtualViewId == INVALID_ID) || !m_manager.isEnabled()) { + Log.w(TAG, "sendEventForVirtualViewId for invalid view"); + return false; + } + + final ViewGroup group = (ViewGroup) m_view.getParent(); + if (group == null) { + Log.w(TAG, "Could not send AccessibilityEvent because group was null. This should really not happen."); + return false; + } + + final AccessibilityEvent event; + event = getEventForVirtualViewId(virtualViewId, eventType); + return group.requestSendAccessibilityEvent(m_view, event); + } + + public void invalidateVirtualViewId(int virtualViewId) + { + sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); + } + + private void setHoveredVirtualViewId(int virtualViewId) + { + if (m_hoveredVirtualViewId == virtualViewId) { + return; + } + + final int previousVirtualViewId = m_hoveredVirtualViewId; + m_hoveredVirtualViewId = virtualViewId; + sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); + sendEventForVirtualViewId(previousVirtualViewId, AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); + } + + private AccessibilityEvent getEventForVirtualViewId(int virtualViewId, int eventType) + { + final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); + + event.setEnabled(true); + event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); + + event.setContentDescription(QtNativeAccessibility.descriptionForAccessibleObject(virtualViewId)); + if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) + Log.w(TAG, "AccessibilityEvent with empty description"); + + event.setPackageName(m_view.getContext().getPackageName()); + event.setSource(m_view, virtualViewId); + return event; + } + + private void dumpNodes(int parentId) + { + Log.i(TAG, "A11Y hierarchy: " + parentId + " parent: " + QtNativeAccessibility.parentId(parentId)); + Log.i(TAG, " desc: " + QtNativeAccessibility.descriptionForAccessibleObject(parentId) + " rect: " + QtNativeAccessibility.screenRect(parentId)); + Log.i(TAG, " NODE: " + getNodeForVirtualViewId(parentId)); + int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(parentId); + for (int i = 0; i < ids.length; ++i) { + Log.i(TAG, parentId + " has child: " + ids[i]); + dumpNodes(ids[i]); + } + } + + private AccessibilityNodeInfo getNodeForView() + { + // Since we don't want the parent to be focusable, but we can't remove + // actions from a node, copy over the necessary fields. + final AccessibilityNodeInfo result = AccessibilityNodeInfo.obtain(m_view); + final AccessibilityNodeInfo source = AccessibilityNodeInfo.obtain(m_view); + m_view.onInitializeAccessibilityNodeInfo(source); + + // Get the actual position on screen, taking the status bar into account. + m_view.getLocationOnScreen(m_globalOffset); + final int offsetX = m_globalOffset[0]; + final int offsetY = m_globalOffset[1]; + + // Copy over parent and screen bounds. + final Rect m_tempParentRect = new Rect(); + source.getBoundsInParent(m_tempParentRect); + result.setBoundsInParent(m_tempParentRect); + + final Rect m_tempScreenRect = new Rect(); + source.getBoundsInScreen(m_tempScreenRect); + m_tempScreenRect.offset(offsetX, offsetY); + result.setBoundsInScreen(m_tempScreenRect); + + // Set up the parent view, if applicable. + final ViewParent parent = m_view.getParent(); + if (parent instanceof View) { + result.setParent((View) parent); + } + + result.setVisibleToUser(source.isVisibleToUser()); + result.setPackageName(source.getPackageName()); + result.setClassName(source.getClassName()); + +// Spit out the entire hierarchy for debugging purposes +// dumpNodes(-1); + + int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(-1); + for (int i = 0; i < ids.length; ++i) + result.addChild(m_view, ids[i]); + + return result; + } + + private AccessibilityNodeInfo getNodeForVirtualViewId(int virtualViewId) + { + final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(); + + node.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); + node.setPackageName(m_view.getContext().getPackageName()); + + if (!QtNativeAccessibility.populateNode(virtualViewId, node)) + return node; + + // set only if valid, otherwise we return a node that is invalid and will crash when accessed + node.setSource(m_view, virtualViewId); + + if (TextUtils.isEmpty(node.getText()) && TextUtils.isEmpty(node.getContentDescription())) + Log.w(TAG, "AccessibilityNodeInfo with empty contentDescription: " + virtualViewId); + + int parentId = QtNativeAccessibility.parentId(virtualViewId); + node.setParent(m_view, parentId); + + Rect screenRect = QtNativeAccessibility.screenRect(virtualViewId); + final int offsetX = m_globalOffset[0]; + final int offsetY = m_globalOffset[1]; + screenRect.offset(offsetX, offsetY); + node.setBoundsInScreen(screenRect); + + Rect rectInParent = screenRect; + Rect parentScreenRect = QtNativeAccessibility.screenRect(parentId); + rectInParent.offset(-parentScreenRect.left, -parentScreenRect.top); + node.setBoundsInParent(rectInParent); + + // Manage internal accessibility focus state. + if (m_focusedVirtualViewId == virtualViewId) { + node.setAccessibilityFocused(true); + node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); + } else { + node.setAccessibilityFocused(false); + node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); + } + + int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(virtualViewId); + for (int i = 0; i < ids.length; ++i) + node.addChild(m_view, ids[i]); + return node; + } + + private AccessibilityNodeProvider m_nodeProvider = new AccessibilityNodeProvider() + { + @Override + public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) + { + if (virtualViewId == View.NO_ID) { + return getNodeForView(); + } + return getNodeForVirtualViewId(virtualViewId); + } + + @Override + public boolean performAction(int virtualViewId, int action, Bundle arguments) + { + boolean handled = false; + //Log.i(TAG, "PERFORM ACTION: " + action + " on " + virtualViewId); + switch (action) { + case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: + // Only handle the FOCUS action if it's placing focus on + // a different view that was previously focused. + if (m_focusedVirtualViewId != virtualViewId) { + m_focusedVirtualViewId = virtualViewId; + m_view.invalidate(); + sendEventForVirtualViewId(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); + handled = true; + } + break; + case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: + if (m_focusedVirtualViewId == virtualViewId) { + m_focusedVirtualViewId = INVALID_ID; + } + // Since we're managing focus at the parent level, we are + // likely to receive a FOCUS action before a CLEAR_FOCUS + // action. We'll give the benefit of the doubt to the + // framework and always handle FOCUS_CLEARED. + m_view.invalidate(); + sendEventForVirtualViewId(virtualViewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + handled = true; + break; + default: + // Let the node provider handle focus for the view node. + if (virtualViewId == View.NO_ID) { + return m_view.performAccessibilityAction(action, arguments); + } + } + handled |= performActionForVirtualViewId(virtualViewId, action, arguments); + + return handled; + } + }; + + protected boolean performActionForVirtualViewId(int virtualViewId, int action, Bundle arguments) + { +// Log.i(TAG, "ACTION " + action + " on " + virtualViewId); +// dumpNodes(virtualViewId); + boolean success = false; + switch (action) { + case AccessibilityNodeInfo.ACTION_CLICK: + success = QtNativeAccessibility.clickAction(virtualViewId); + if (success) + sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_CLICKED); + break; + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: + success = QtNativeAccessibility.scrollForward(virtualViewId); + if (success) + sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_SCROLLED); + break; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: + success = QtNativeAccessibility.scrollBackward(virtualViewId); + if (success) + sendEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_VIEW_SCROLLED); + break; + } + return success; + } +} diff --git a/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java new file mode 100644 index 0000000000..bfda2d55b7 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Android port of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +package org.qtproject.qt5.android.accessibility; + +import android.graphics.Rect; +import android.view.accessibility.AccessibilityNodeInfo; + +class QtNativeAccessibility +{ + static native void setActive(boolean enable); + static native int[] childIdListForAccessibleObject(int objectId); + static native int parentId(int objectId); + static native String descriptionForAccessibleObject(int objectId); + static native Rect screenRect(int objectId); + static native int hitTest(float x, float y); + static native boolean clickAction(int objectId); + static native boolean scrollForward(int objectId); + static native boolean scrollBackward(int objectId); + + static native boolean populateNode(int objectId, AccessibilityNodeInfo node); +} diff --git a/src/android/java/res/values-ro/strings.xml b/src/android/java/res/values-ro/strings.xml index f88a442b35..fef52ad3bd 100644 --- a/src/android/java/res/values-ro/strings.xml +++ b/src/android/java/res/values-ro/strings.xml @@ -3,4 +3,5 @@ Serviciul Ministro nu poate fi găsit.\nAplicaţia nu poate porni. Această aplicaţie necesită serviciul Ministro.\nDoriţi să-l instalaţi? Aplicaţia dumneavoastră a întâmpinat o eroare fatală şi nu poate continua. + Versiune Android nesuportată. diff --git a/src/android/java/res/values/strings.xml b/src/android/java/res/values/strings.xml index fcc3eb097b..95b3385924 100644 --- a/src/android/java/res/values/strings.xml +++ b/src/android/java/res/values/strings.xml @@ -4,4 +4,5 @@ Can\'t find Ministro service.\nThe application can\'t start. This application requires Ministro service. Would you like to install it? Your application encountered a fatal error and cannot continue. + Unsupported Android version. diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java index e6527c440a..0859318fe1 100644 --- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java +++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtActivity.java @@ -183,11 +183,7 @@ public class QtActivity extends Activity public QtActivity() { - if (Build.VERSION.SDK_INT <= 10) { - QT_ANDROID_THEMES = new String[] {"Theme_Light"}; - QT_ANDROID_DEFAULT_THEME = "Theme_Light"; - } - else if ((Build.VERSION.SDK_INT >= 11 && Build.VERSION.SDK_INT <= 13) || Build.VERSION.SDK_INT >= 21){ + if (Build.VERSION.SDK_INT >= 21) { QT_ANDROID_THEMES = new String[] {"Theme_Holo_Light"}; QT_ANDROID_DEFAULT_THEME = "Theme_Holo_Light"; } else { @@ -843,7 +839,6 @@ public class QtActivity extends Activity public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - try { m_activityInfo = getPackageManager().getActivityInfo(getComponentName(), PackageManager.GET_META_DATA); for (Field f : Class.forName("android.R$style").getDeclaredFields()) { @@ -858,21 +853,30 @@ public class QtActivity extends Activity return; } + if (Build.VERSION.SDK_INT < 16) { + // fatal error, show the error and quit + AlertDialog errorDialog = new AlertDialog.Builder(QtActivity.this).create(); + if (m_activityInfo.metaData.containsKey("android.app.unsupported_android_version")) + errorDialog.setMessage(m_activityInfo.metaData.getString("android.app.unsupported_android_version")); + else + errorDialog.setMessage("Unsupported Android version."); + errorDialog.setButton(getResources().getString(android.R.string.ok), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + errorDialog.show(); + return; + } + try { setTheme(Class.forName("android.R$style").getDeclaredField(QT_ANDROID_DEFAULT_THEME).getInt(null)); } catch (Exception e) { e.printStackTrace(); } - if (Build.VERSION.SDK_INT > 10) { - try { - requestWindowFeature(Window.class.getField("FEATURE_ACTION_BAR").getInt(null)); - } catch (Exception e) { - e.printStackTrace(); - } - } else { - requestWindowFeature(Window.FEATURE_NO_TITLE); - } + requestWindowFeature(Window.FEATURE_ACTION_BAR); if (QtApplication.m_delegateObject != null && QtApplication.onCreate != null) { QtApplication.invokeDelegateMethod(QtApplication.onCreate, savedInstanceState); diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml index 262a5f6dba..2a6d0b6fa3 100644 --- a/src/android/templates/AndroidManifest.xml +++ b/src/android/templates/AndroidManifest.xml @@ -50,7 +50,7 @@ - +