diff options
Diffstat (limited to 'src/android/jar/src/org/qtproject/qt5')
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()); + } } } |