diff options
Diffstat (limited to 'src/android/jar/src/org/qtproject')
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/ExtractStyle.java | 26 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java | 168 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java | 81 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/QtNative.java | 18 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu14.java | 69 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/QtSurface.java | 3 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java | 416 | ||||
-rw-r--r-- | src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java (renamed from src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu.java) | 46 |
8 files changed, 542 insertions, 285 deletions
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 dd5a7b4fec..0a10a12660 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) @@ -908,6 +876,23 @@ public class QtActivityDelegate } catch (Exception e) { e.printStackTrace(); } + + // if splash screen is defined, then show it + // Note: QtActivity handles settting the splash screen + // in onCreate, change that too if you are changing + // how the splash screen should be displayed + try { + if (m_surfaces.size() == 0) { + ActivityInfo info = m_activity.getPackageManager().getActivityInfo(m_activity.getComponentName(), PackageManager.GET_META_DATA); + if (info.metaData.containsKey("android.app.splash_screen_drawable")) + m_activity.getWindow().setBackgroundDrawableResource(info.metaData.getInt("android.app.splash_screen_drawable")); + else + m_activity.getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000)); + } + } catch (Exception e) { + e.printStackTrace(); + } + int rotation = m_activity.getWindowManager().getDefaultDisplay().getRotation(); if (rotation != m_currentRotation) { QtNative.handleOrientationChanged(rotation, m_nativeOrientation); @@ -1102,17 +1087,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, @@ -1148,15 +1125,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); } @@ -1166,46 +1150,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 2349ea6db1..5ff5bbc32f 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -333,16 +333,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/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 <bogdan@kde.org> -** 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/QtPopupMenu.java b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java index d89b454b77..bfda2d55b7 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtPopupMenu.java +++ b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2014 BogDan Vatra <bogdan@kde.org> +** 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. @@ -31,36 +31,22 @@ ** ****************************************************************************/ -package org.qtproject.qt5.android; +package org.qtproject.qt5.android.accessibility; -import android.view.MenuItem; -import android.view.View; -import android.widget.PopupMenu; +import android.graphics.Rect; +import android.view.accessibility.AccessibilityNodeInfo; -public class QtPopupMenu { - private QtPopupMenu() { } +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); - 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(); - } + static native boolean populateNode(int objectId, AccessibilityNodeInfo node); } |