diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-11-26 22:30:27 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2013-11-26 22:35:48 +0100 |
commit | 4a8273a6fc2e741e811cf5dabc9a3c240306cf7f (patch) | |
tree | 2148abc88f8543eecdc0b97b2dd92594836af9b2 /src/android/jar/src | |
parent | 036c5db468164297d213764c59a4b59daa76d90a (diff) | |
parent | 1c2be58fecaff1de5f2849192eb712984ebd59bd (diff) |
Merge remote-tracking branch 'origin/stable' into dev
For the conflicts in msvc_nmake.cpp the ifdefs are extended since we
need to support windows phone in the target branch while it is not there
in the current stable branch (as of Qt 5.2).
Conflicts:
configure
qmake/generators/win32/msvc_nmake.cpp
src/3rdparty/angle/src/libEGL/Surface.cpp
src/angle/src/common/common.pri
src/corelib/global/qglobal.h
src/corelib/io/qstandardpaths.cpp
src/plugins/platforms/qnx/qqnxintegration.cpp
src/plugins/platforms/qnx/qqnxscreeneventhandler.h
src/plugins/platforms/xcb/qglxintegration.h
src/widgets/kernel/win.pri
tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp
tests/auto/corelib/tools/qdatetime/tst_qdatetime.cpp
tests/auto/gui/text/qtextdocument/tst_qtextdocument.cpp
tools/configure/configureapp.cpp
Change-Id: I00b579eefebaf61d26ab9b00046d2b5bd5958812
Diffstat (limited to 'src/android/jar/src')
6 files changed, 657 insertions, 93 deletions
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 11af4d4280..3dcffeb07d 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -42,13 +42,6 @@ package org.qtproject.qt5.android; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Iterator; - import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; @@ -57,6 +50,8 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; import android.text.method.MetaKeyKeyListener; import android.util.DisplayMetrics; import android.util.Log; @@ -66,11 +61,19 @@ import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; +import android.view.Surface; import android.view.View; +import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; -import android.view.Surface; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; public class QtActivityDelegate { @@ -109,8 +112,9 @@ public class QtActivityDelegate private boolean m_quitApp = true; private Process m_debuggerProcess = null; // debugger process - public boolean m_keyboardIsVisible = false; - public boolean m_keyboardIsHiding = false; + private boolean m_keyboardIsVisible = false; + public boolean m_backKeyPressedSent = false; + public QtLayout getQtLayout() { @@ -173,6 +177,13 @@ public class QtActivityDelegate private final int ApplicationInactive = 0x2; private final int ApplicationActive = 0x4; + public void setKeyboardVisibility(boolean visibility) + { + if (m_keyboardIsVisible == visibility) + return; + m_keyboardIsVisible = visibility; + QtNative.keyboardVisibilityChanged(m_keyboardIsVisible); + } public void resetSoftwareKeyboard() { if (m_imm == null) @@ -181,6 +192,7 @@ public class QtActivityDelegate @Override public void run() { m_imm.restartInput(m_editText); + m_editText.m_optionsChanged = false; } }, 5); } @@ -253,15 +265,25 @@ public class QtActivityDelegate m_editText.postDelayed(new Runnable() { @Override public void run() { - m_imm.showSoftInput(m_editText, 0); - m_keyboardIsVisible = true; - m_keyboardIsHiding = false; - m_editText.postDelayed(new Runnable() { + m_imm.showSoftInput(m_editText, 0, new ResultReceiver(new Handler()) { @Override - public void run() { - m_imm.restartInput(m_editText); + protected void onReceiveResult(int resultCode, Bundle resultData) { + switch (resultCode) { + case InputMethodManager.RESULT_SHOWN: + case InputMethodManager.RESULT_UNCHANGED_SHOWN: + setKeyboardVisibility(true); + break; + case InputMethodManager.RESULT_HIDDEN: + case InputMethodManager.RESULT_UNCHANGED_HIDDEN: + setKeyboardVisibility(false); + break; + } } - }, 25); + }); + if (m_editText.m_optionsChanged) { + m_imm.restartInput(m_editText); + m_editText.m_optionsChanged = false; + } } }, 15); } @@ -270,9 +292,21 @@ public class QtActivityDelegate { if (m_imm == null) return; - m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0); - m_keyboardIsVisible = false; - m_keyboardIsHiding = false; + m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0, new ResultReceiver( new Handler()){ + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + switch (resultCode) { + case InputMethodManager.RESULT_SHOWN: + case InputMethodManager.RESULT_UNCHANGED_SHOWN: + setKeyboardVisibility(true); + break; + case InputMethodManager.RESULT_HIDDEN: + case InputMethodManager.RESULT_UNCHANGED_HIDDEN: + setKeyboardVisibility(false); + break; + } + } + }); } public boolean isSoftwareKeyboardVisible() @@ -362,7 +396,7 @@ public class QtActivityDelegate + "\tNECESSITAS_API_LEVEL=" + necessitasApiLevel + "\tHOME=" + m_activity.getFilesDir().getAbsolutePath() + "\tTMPDIR=" + m_activity.getFilesDir().getAbsolutePath(); - if (android.os.Build.VERSION.SDK_INT < 14) + 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"; @@ -378,6 +412,7 @@ public class QtActivityDelegate m_applicationParameters = loaderParams.getString(APPLICATION_PARAMETERS_KEY); else m_applicationParameters = ""; + setActionBarVisibility(false); return true; } @@ -585,9 +620,9 @@ public class QtActivityDelegate } m_layout = new QtLayout(m_activity); m_surface = new QtSurface(m_activity, 0); - m_editText = new QtEditText(m_activity); + m_editText = new QtEditText(m_activity, this); m_imm = (InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE); - m_layout.addView(m_surface,0); + m_layout.addView(m_surface, 0); m_activity.setContentView(m_layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT)); @@ -717,8 +752,12 @@ public class QtActivityDelegate } m_lastChar = lc; - if (keyCode != KeyEvent.KEYCODE_BACK) - QtNative.keyDown(keyCode, c, event.getMetaState()); + if (keyCode == KeyEvent.KEYCODE_BACK) { + m_backKeyPressedSent = !m_keyboardIsVisible; + if (!m_backKeyPressedSent) + return true; + } + QtNative.keyDown(keyCode, c, event.getMetaState()); return true; } @@ -737,8 +776,9 @@ public class QtActivityDelegate } } - if (keyCode == KeyEvent.KEYCODE_BACK && m_keyboardIsVisible && !m_keyboardIsHiding) { + if (keyCode == KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) { hideSoftwareKeyboard(); + setKeyboardVisibility(false); return true; } @@ -775,7 +815,10 @@ public class QtActivityDelegate public boolean onPrepareOptionsMenu(Menu menu) { m_opionsMenuIsVisible = true; - return QtNative.onPrepareOptionsMenu(menu); + boolean res = QtNative.onPrepareOptionsMenu(menu); + if (!res || menu.size() == 0) + setActionBarVisibility(false); + return res; } public boolean onOptionsItemSelected(MenuItem item) @@ -791,8 +834,17 @@ public class QtActivityDelegate public void resetOptionsMenu() { - if (m_opionsMenuIsVisible) - m_activity.closeOptionsMenu(); + setActionBarVisibility(true); + if (Build.VERSION.SDK_INT > 10) { + try { + Activity.class.getMethod("invalidateOptionsMenu").invoke(m_activity); + } catch (Exception e) { + e.printStackTrace(); + } + } + else + if (m_opionsMenuIsVisible) + m_activity.closeOptionsMenu(); } private boolean m_contextMenuVisible = false; public void onCreateContextMenu(ContextMenu menu, @@ -833,4 +885,46 @@ 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(); + } + } + } } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java b/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java index b95e0c070c..593746aac9 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtEditText.java @@ -50,33 +50,47 @@ import android.view.inputmethod.InputConnection; public class QtEditText extends View { - QtInputConnection m_inputConnection; int m_initialCapsMode = 0; int m_imeOptions = 0; int m_inputType = InputType.TYPE_CLASS_TEXT; + boolean m_optionsChanged = false; + QtActivityDelegate m_activityDelegate; public void setImeOptions(int m_imeOptions) { + if (m_imeOptions == this.m_imeOptions) + return; this.m_imeOptions = m_imeOptions; + m_optionsChanged = true; } public void setInitialCapsMode(int m_initialCapsMode) { + if (m_initialCapsMode == this.m_initialCapsMode) + return; this.m_initialCapsMode = m_initialCapsMode; + m_optionsChanged = true; } public void setInputType(int m_inputType) { + if (m_inputType == this.m_inputType) + return; this.m_inputType = m_inputType; + m_optionsChanged = true; } - public QtEditText(Context context) + public QtEditText(Context context, QtActivityDelegate activityDelegate) { super(context); setFocusable(true); setFocusableInTouchMode(true); - m_inputConnection = new QtInputConnection(this); + m_activityDelegate = activityDelegate; + } + public QtActivityDelegate getActivityDelegate() + { + return m_activityDelegate; } @Override @@ -86,8 +100,9 @@ public class QtEditText extends View outAttrs.imeOptions = m_imeOptions; outAttrs.initialCapsMode = m_initialCapsMode; outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI; - return m_inputConnection; + return new QtInputConnection(this); } + // // DEBUG CODE // @Override // protected void onDraw(Canvas canvas) { diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java index f251369737..4b2d50ca1f 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java @@ -43,8 +43,6 @@ package org.qtproject.qt5.android; import android.content.Context; -import android.os.Build; -import android.view.View; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.ExtractedText; @@ -82,6 +80,22 @@ class QtNativeInputConnection static native boolean paste(); } +class HideKeyboardRunnable implements Runnable { + private QtInputConnection m_connection; + HideKeyboardRunnable(QtInputConnection connection) + { + m_connection = connection; + } + + @Override + public void run() { + if (m_connection.getInputState() == QtInputConnection.InputStates.Hiding) { + QtNative.activityDelegate().setKeyboardVisibility(false); + m_connection.reset(); + } + } +} + public class QtInputConnection extends BaseInputConnection { private static final int ID_SELECT_ALL = android.R.id.selectAll; @@ -92,67 +106,83 @@ public class QtInputConnection extends BaseInputConnection private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod; private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary; - View m_view; - boolean m_closing; - public QtInputConnection(View targetView) + + enum InputStates { Visible, FinishComposing, Hiding }; + + private QtEditText m_view = null; + private InputStates m_inputState = InputStates.Visible; + + public void reset() + { + m_inputState = InputStates.Visible; + } + + public InputStates getInputState() + { + return m_inputState; + } + + private void setClosing(boolean closing) + { + if (closing && m_inputState == InputStates.Hiding) + return; + + if (closing && m_inputState == InputStates.FinishComposing && m_view.getActivityDelegate().isSoftwareKeyboardVisible()) { + m_view.postDelayed(new HideKeyboardRunnable(this), 100); + m_inputState = InputStates.Hiding; + } else { + if (m_inputState == InputStates.Hiding) + QtNative.activityDelegate().setKeyboardVisibility(true); + m_inputState = closing ? InputStates.FinishComposing : InputStates.Visible; + } + } + + public QtInputConnection(QtEditText targetView) { super(targetView, true); m_view = targetView; - m_closing = false; } @Override public boolean beginBatchEdit() { - m_closing = false; + setClosing(false); return true; } @Override public boolean endBatchEdit() { - m_closing = false; +// setClosing(false); return true; } @Override public boolean commitCompletion(CompletionInfo text) { - m_closing = false; + setClosing(false); return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition()); } @Override public boolean commitText(CharSequence text, int newCursorPosition) { - m_closing = false; + setClosing(false); return QtNativeInputConnection.commitText(text.toString(), newCursorPosition); } @Override public boolean deleteSurroundingText(int leftLength, int rightLength) { - m_closing = false; + setClosing(false); return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength); } @Override public boolean finishComposingText() { - if (m_closing) { - QtNative.activityDelegate().m_keyboardIsHiding = true; - m_view.postDelayed(new Runnable() { - @Override - public void run() { - if (QtNative.activityDelegate().m_keyboardIsHiding) - QtNative.activityDelegate().m_keyboardIsVisible=false; - } - }, 5000); // it seems finishComposingText comes musch faster than onKeyUp event, - // so we must delay hide notification - m_closing = false; - } else { - m_closing = true; - } + // on some/all android devices hide event is not coming, but instead finishComposingText() is called twice + setClosing(true); return QtNativeInputConnection.finishComposingText(); } @@ -234,18 +264,21 @@ public class QtInputConnection extends BaseInputConnection @Override public boolean setComposingText(CharSequence text, int newCursorPosition) { + setClosing(false); return QtNativeInputConnection.setComposingText(text.toString(), newCursorPosition); } @Override public boolean setComposingRegion(int start, int end) { + setClosing(false); return QtNativeInputConnection.setComposingRegion(start, end); } @Override public boolean setSelection(int start, int end) { + setClosing(false); return QtNativeInputConnection.setSelection(start, end); } } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java b/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java new file mode 100644 index 0000000000..6ee1304c12 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt5/android/QtMessageDialogHelper.java @@ -0,0 +1,425 @@ +/**************************************************************************** + ** + ** Copyright (C) 2013 BogDan Vatra <bogdan@kde.org> + ** Contact: http://www.qt-project.org/legal + ** + ** This file is part of the Android port of the Qt Toolkit. + ** + ** $QT_BEGIN_LICENSE:LGPL$ + ** 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 Digia. For licensing terms and + ** conditions see http://qt.digia.com/licensing. For further information + ** use the contact form at http://qt.digia.com/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 as published by the Free Software + ** Foundation and appearing in the file LICENSE.LGPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU Lesser General Public License version 2.1 requirements + ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. + ** + ** In addition, as a special exception, Digia gives you certain additional + ** rights. These rights are described in the Digia Qt LGPL Exception + ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. + ** + ** GNU General Public License Usage + ** Alternatively, this file may be used under the terms of the GNU + ** General Public License version 3.0 as published by the Free Software + ** Foundation and appearing in the file LICENSE.GPL included in the + ** packaging of this file. Please review the following information to + ** ensure the GNU General Public License version 3.0 requirements will be + ** met: http://www.gnu.org/copyleft/gpl.html. + ** + ** + ** $QT_END_LICENSE$ + ** + ****************************************************************************/ + + +package org.qtproject.qt5.android; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.ClipboardManager; +import android.util.TypedValue; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; + +class QtNativeDialogHelper +{ + static native void dialogResult(long handler, int buttonID); +} + +class ButtonStruct implements View.OnClickListener +{ + ButtonStruct(QtMessageDialogHelper dialog, int id, String text) + { + m_dialog = dialog; + m_id = id; + m_text = text; + } + QtMessageDialogHelper m_dialog; + private int m_id; + String m_text; + + @Override + public void onClick(View view) { + QtNativeDialogHelper.dialogResult(m_dialog.handler(), m_id); + } +} + +public class QtMessageDialogHelper +{ + + public QtMessageDialogHelper(Activity activity) + { + m_activity = activity; + } + + + public void setIcon(int icon) + { + m_icon = icon; + + } + + private Drawable getIconDrawable() + { + 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(); + } + } + + // Information, Warning, Critical, Question + switch (m_icon) + { + case 1: // Information + try { + return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_dialog_info").getInt(null)); + } catch (Exception e) { + e.printStackTrace(); + } + break; + case 2: // Warning +// try { +// return Class.forName("android.R$drawable").getDeclaredField("stat_sys_warning").getInt(null); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// break; + case 3: // Critical + try { + return m_activity.getResources().getDrawable(Class.forName("android.R$drawable").getDeclaredField("ic_dialog_alert").getInt(null)); + } 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)); + } catch (Exception e) { + e.printStackTrace(); + } + break; + } + return null; + } + + public void setTile(String title) + { + m_title = title; + } + + public void setText(String text) + { + m_text = text; + } + + public void setInformativeText(String informativeText) + { + m_informativeText = informativeText; + } + + public void setDetailedText(String text) + { + m_detailedText = text; + } + + public void addButton(int id, String text) + { + if (m_buttonsList == null) + m_buttonsList = new ArrayList<ButtonStruct>(); + m_buttonsList.add(new ButtonStruct(this, id, text)); + } + + private void setTextAppearance(TextView view, String attr, String style) + { + try { + int[] attrs = (int[]) Class.forName("android.R$styleable").getDeclaredField("TextAppearance").get(null); + final TypedArray a = m_theme.obtainStyledAttributes(null, + attrs, + Class.forName("android.R$attr").getDeclaredField(attr).getInt(null), + Class.forName("android.R$style").getDeclaredField(style).getInt(null)); + final int textSize = a.getDimensionPixelSize( + Class.forName("android.R$styleable").getDeclaredField("TextAppearance_textSize").getInt(null), 0); + if (textSize != 0) + view.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); + + final int textColor = a.getColor( + Class.forName("android.R$styleable").getDeclaredField("TextAppearance_textColor").getInt(null), 0x3138); + if (textColor != 0x3138) + view.setTextColor(textColor); + + a.recycle(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private Drawable getStyledDrawable(String drawable) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException + { + int[] attrs = {Class.forName("android.R$attr").getDeclaredField(drawable).getInt(null)}; + final TypedArray a = m_theme.obtainStyledAttributes(attrs); + Drawable d = a.getDrawable(0); + a.recycle(); + return d; + } + + + public void show(long handler) + { + m_handler = handler; + m_activity.runOnUiThread( new Runnable() { + @Override + public void run() { + if (m_dialog != null && m_dialog.isShowing()) + m_dialog.dismiss(); + + m_dialog = new AlertDialog.Builder(m_activity).create(); + m_theme = m_dialog.getWindow().getContext().getTheme(); + + if (m_title != null) + m_dialog.setTitle(m_title); + m_dialog.setOnCancelListener( new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialogInterface) { + QtNativeDialogHelper.dialogResult(handler(), -1); + } + }); + m_dialog.setCancelable(m_buttonsList == null); + m_dialog.setCanceledOnTouchOutside(m_buttonsList == null); + m_dialog.setIcon(getIconDrawable()); + ScrollView scrollView = new ScrollView(m_activity); + RelativeLayout dialogLayout = new RelativeLayout(m_activity); + int id = 1; + View lastView = null; + View.OnLongClickListener copyText = new View.OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + TextView tv = (TextView)view; + if (tv != null) { + ClipboardManager cm = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE); + cm.setText(tv.getText()); + } + return true; + } + }; + if (m_text != null) + { + TextView view = new TextView(m_activity); + view.setId(id++); + view.setOnLongClickListener(copyText); + view.setLongClickable(true); + + view.setText(m_text); + setTextAppearance(view, "textAppearanceMedium", "TextAppearance_Medium"); + + RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + layout.setMargins(16, 8, 16, 8); + layout.addRule(RelativeLayout.ALIGN_PARENT_TOP); + dialogLayout.addView(view, layout); + lastView = view; + } + + if (m_informativeText != null) + { + TextView view= new TextView(m_activity); + view.setId(id++); + view.setOnLongClickListener(copyText); + view.setLongClickable(true); + + view.setText(m_informativeText); + setTextAppearance(view, "textAppearanceMedium", "TextAppearance_Medium"); + + RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + layout.setMargins(16, 8, 16, 8); + if (lastView != null) + layout.addRule(RelativeLayout.BELOW, lastView.getId()); + else + layout.addRule(RelativeLayout.ALIGN_PARENT_TOP); + dialogLayout.addView(view, layout); + lastView = view; + } + + if (m_detailedText != null) + { + TextView view= new TextView(m_activity); + view.setId(id++); + view.setOnLongClickListener(copyText); + view.setLongClickable(true); + + view.setText(m_detailedText); + setTextAppearance(view, "textAppearanceSmall", "TextAppearance_Small"); + + RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + layout.setMargins(16, 8, 16, 8); + if (lastView != null) + layout.addRule(RelativeLayout.BELOW, lastView.getId()); + else + layout.addRule(RelativeLayout.ALIGN_PARENT_TOP); + dialogLayout.addView(view, layout); + lastView = view; + } + + if (m_buttonsList != null) + { + LinearLayout buttonsLayout = new LinearLayout(m_activity); + buttonsLayout.setOrientation(LinearLayout.HORIZONTAL); + buttonsLayout.setId(id++); + boolean firstButton = true; + 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 { + bv = new Button(m_activity); + } + + bv.setText(button.m_text); + bv.setOnClickListener(button); + if (!firstButton) // first button + { + 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(); + } + } + } + LinearLayout.LayoutParams layout = null; + layout = new LinearLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT, 1.0f); + buttonsLayout.addView(bv, layout); + 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(); + } + } + RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT); + if (lastView != null) { + relativeParams.addRule(RelativeLayout.BELOW, lastView.getId()); + } + 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); + dialogLayout.addView(buttonsLayout, relativeParams); + } + scrollView.addView(dialogLayout); + m_dialog.setView(scrollView); + m_dialog.show(); + } + }); + } + + public void hide() + { + m_activity.runOnUiThread( new Runnable() { + @Override + public void run() { + if (m_dialog != null && m_dialog.isShowing()) + m_dialog.dismiss(); + reset(); + } + }); + } + + public long handler() + { + return m_handler; + } + + public void reset() + { + m_icon = 0; + m_title = null; + m_text = null; + m_informativeText = null; + m_detailedText = null; + m_buttonsList = null; + m_dialog = null; + m_handler = 0; + } + + private Activity m_activity; + private int m_icon = 0; + private String m_title, m_text, m_informativeText, m_detailedText; + private ArrayList<ButtonStruct> m_buttonsList; + private AlertDialog m_dialog; + private long m_handler = 0; + private Resources.Theme m_theme; +} 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 1385c90e3e..57f3642b56 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -50,7 +50,6 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.text.ClipboardManager; import android.util.Log; import android.view.ContextMenu; @@ -110,9 +109,13 @@ public class QtNative public static void openURL(String url) { - Uri uri = Uri.parse(url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - activity().startActivity(intent); + try { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + activity().startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + } } // this method loads full path libs @@ -419,30 +422,21 @@ public class QtNative private static boolean isSoftwareKeyboardVisible() { - Semaphore semaphore = new Semaphore(1); - Boolean ret = false; - class RunnableRes implements Runnable { - @SuppressWarnings("unused") - Boolean returnValue = null; - Semaphore semaphore = null; - RunnableRes(Boolean ret, Semaphore sem) { - semaphore = sem; - returnValue = ret; - } + final Semaphore semaphore = new Semaphore(0); + final Boolean[] ret = {false}; + runAction(new Runnable() { @Override public void run() { - returnValue = m_activityDelegate.isSoftwareKeyboardVisible(); + ret[0] = m_activityDelegate.isSoftwareKeyboardVisible(); semaphore.release(); } - } - - runAction(new RunnableRes(ret, semaphore)); + }); try { semaphore.acquire(); } catch (Exception e) { e.printStackTrace(); } - return ret; + return ret[0]; } private static void setFullScreen(final boolean fullScreen) @@ -458,7 +452,7 @@ public class QtNative private static void registerClipboardManager() { - final Semaphore semaphore = new Semaphore(1); + final Semaphore semaphore = new Semaphore(0); runAction(new Runnable() { @Override public void run() { @@ -569,6 +563,7 @@ public class QtNative // keyboard methods public static native void keyDown(int key, int unicode, int modifier); public static native void keyUp(int key, int unicode, int modifier); + public static native void keyboardVisibilityChanged(boolean visibility); // keyboard methods // surface methods 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 cd0bddf2c8..c499dc3898 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtSurface.java @@ -117,21 +117,23 @@ public class QtSurface extends SurfaceView implements SurfaceHolder.Callback // Initialize Accessibility // The accessibility code depends on android API level 16, so dynamically resolve it - try { - final String a11yDelegateClassName = "org.qtproject.qt5.android.accessibility.QtAccessibilityDelegate"; - Class<?> qtDelegateClass = Class.forName(a11yDelegateClassName); - Constructor constructor = qtDelegateClass.getConstructor(Class.forName("android.view.View")); - m_accessibilityDelegate = constructor.newInstance(this); - - Class a11yDelegateClass = Class.forName("android.view.View$AccessibilityDelegate"); - Method setDelegateMethod = this.getClass().getMethod("setAccessibilityDelegate", a11yDelegateClass); - setDelegateMethod.invoke(this, m_accessibilityDelegate); - } 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()); + if (android.os.Build.VERSION.SDK_INT >= 16) { + try { + final String a11yDelegateClassName = "org.qtproject.qt5.android.accessibility.QtAccessibilityDelegate"; + Class<?> qtDelegateClass = Class.forName(a11yDelegateClassName); + Constructor constructor = qtDelegateClass.getConstructor(Class.forName("android.view.View")); + m_accessibilityDelegate = constructor.newInstance(this); + + Class a11yDelegateClass = Class.forName("android.view.View$AccessibilityDelegate"); + Method setDelegateMethod = this.getClass().getMethod("setAccessibilityDelegate", a11yDelegateClass); + setDelegateMethod.invoke(this, m_accessibilityDelegate); + } 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()); + } } } |