diff options
Diffstat (limited to 'tests/auto/android/src/org')
4 files changed, 1120 insertions, 0 deletions
diff --git a/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java b/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java new file mode 100644 index 0000000000..ae4ca3c30a --- /dev/null +++ b/tests/auto/android/src/org/qtproject/qt5/android/QtActivity.java @@ -0,0 +1,327 @@ +/* + Copyright (c) 2012, BogDan Vatra <bogdan@kde.org> + Contact: http://www.qt-project.org/legal + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package org.qtproject.qt5.android; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; + +import org.qtproject.qt5.android.tests.R; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Bundle; +import android.text.method.MetaKeyKeyListener; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.Window; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; + +public class QtActivity extends Activity { + private int m_id =- 1; + private boolean softwareKeyboardIsVisible = false; + private long m_metaState; + private int m_lastChar = 0; + private boolean m_fullScreen = false; + private boolean m_started = false; + private QtSurface m_surface = null; + private boolean m_usesGL = false; + private void loadQtLibs(String[] libs, String environment, String params, String mainLib, String nativeLibDir) throws Exception + { + QtNative.loadQtLibraries(libs); + // start application + + final String envPaths = "NECESSITAS_API_LEVEL=2\tHOME=" + getDir("files", MODE_WORLD_WRITEABLE).getAbsolutePath() + + "\tTMPDIR=" + getDir("files", MODE_WORLD_WRITEABLE).getAbsolutePath() + + "\tCACHE_PATH=" + getDir("files", MODE_WORLD_WRITEABLE).getAbsolutePath(); + if (environment != null && environment.length() > 0) + environment = envPaths + "\t" + environment; + else + environment = envPaths; + + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + QtNative.startApplication(params, environment, mainLib, nativeLibDir); + m_surface.applicationStarted(m_usesGL); + m_started = true; + } + + private boolean m_quitApp = true; + private Process m_debuggerProcess = null; // debugger process + + private void startApp(final boolean firstStart) + { + try { + String qtLibs[] = getResources().getStringArray(R.array.qt_libs); + ArrayList<String> libraryList = new ArrayList<String>(); + for (int i = 0; i < qtLibs.length; i++) + libraryList.add("/data/local/qt/lib/lib" + qtLibs[i] + ".so"); + + String mainLib = null; + String nativeLibDir = null; + if (getIntent().getExtras() != null) { + if (getIntent().getExtras().containsKey("extra_libs")) { + String extra_libs = getIntent().getExtras().getString("extra_libs"); + for (String lib : extra_libs.split(":")) + libraryList.add(lib); + } + if (getIntent().getExtras().containsKey("lib_name")) { + mainLib = getIntent().getExtras().getString("lib_name"); + int slash = mainLib.lastIndexOf("/"); + if (slash >= 0) { + nativeLibDir = mainLib.substring(0, slash+1); + mainLib = mainLib.substring(slash+1+3, mainLib.length()-3); //remove lib and .so + } else { + nativeLibDir = ""; + } + } + + if (getIntent().getExtras().containsKey("needsOpenGl")) + m_usesGL = getIntent().getExtras().getBoolean("needsOpenGl"); + } else { + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + System.exit(0); + } + String[] libs = new String[libraryList.size()]; + libs = libraryList.toArray(libs); + loadQtLibs(libs, "QML_IMPORT_PATH=/data/local/qt/imports\tQT_PLUGIN_PATH=/data/local/qt/plugins", + "-xml\t-silent\t-o\toutput.xml", mainLib, nativeLibDir); + } catch (Exception e) { + Log.e(QtNative.QtTAG, "Can't create main activity", e); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + getDir("files", MODE_WORLD_WRITEABLE); + requestWindowFeature(Window.FEATURE_NO_TITLE); + m_quitApp = true; + QtNative.setMainActivity(this); + if (null == getLastNonConfigurationInstance()) { + DisplayMetrics metrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(metrics); + QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels, + metrics.widthPixels, metrics.heightPixels, + metrics.xdpi, metrics.ydpi); + } + m_surface = new QtSurface(this, m_id); + setContentView(m_surface); + if (null == getLastNonConfigurationInstance()) + startApp(true); + } + + public QtSurface getQtSurface() + { + return m_surface; + } + + @Override + public Object onRetainNonConfigurationInstance() + { + super.onRetainNonConfigurationInstance(); + m_quitApp = false; + return true; + } + + @Override + protected void onDestroy() + { + QtNative.setMainActivity(null); + super.onDestroy(); + if (m_quitApp) { + Log.i(QtNative.QtTAG, "onDestroy"); + if (m_debuggerProcess != null) + m_debuggerProcess.destroy(); + System.exit(0);// FIXME remove it or find a better way + } + QtNative.setMainActivity(null); + } + + @Override + protected void onResume() + { + // fire all lostActions + synchronized (QtNative.m_mainActivityMutex) { + Iterator<Runnable> itr = QtNative.getLostActions().iterator(); + while (itr.hasNext()) + runOnUiThread(itr.next()); + if (m_started) { + QtNative.clearLostActions(); + QtNative.updateWindow(); + } + } + super.onResume(); + } + + public void redrawWindow(int left, int top, int right, int bottom) + { + m_surface.drawBitmap(new Rect(left, top, right, bottom)); + } + + public void setFullScreen(boolean enterFullScreen) + { + if (m_fullScreen == enterFullScreen) + return; + if (m_fullScreen = enterFullScreen) + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + else + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + @Override + protected void onSaveInstanceState(Bundle outState) + { + super.onSaveInstanceState(outState); + outState.putBoolean("FullScreen", m_fullScreen); + outState.putBoolean("Started", m_started); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) + { + super.onRestoreInstanceState(savedInstanceState); + setFullScreen(savedInstanceState.getBoolean("FullScreen")); + m_started = savedInstanceState.getBoolean("Started"); + if (m_started) + m_surface.applicationStarted(true); + } + + public void showSoftwareKeyboard() + { + softwareKeyboardIsVisible = true; + InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); + } + + public void resetSoftwareKeyboard() + { + } + + public void hideSoftwareKeyboard() + { + if (softwareKeyboardIsVisible) { + InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + imm.toggleSoftInput(0, 0); + } + softwareKeyboardIsVisible = false; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) + { + if (m_started && event.getAction() == KeyEvent.ACTION_MULTIPLE && + event.getCharacters() != null && + event.getCharacters().length() == 1 && + event.getKeyCode() == 0) { + Log.i(QtNative.QtTAG, "dispatchKeyEvent at MULTIPLE with one character: " + event.getCharacters()); + QtNative.keyDown(0, event.getCharacters().charAt(0), event.getMetaState()); + QtNative.keyUp(0, event.getCharacters().charAt(0), event.getMetaState()); + } + + return super.dispatchKeyEvent(event); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + if (!m_started) + return false; + m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event); + int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(m_metaState)); + int lc = c; + m_metaState = MetaKeyKeyListener.adjustMetaAfterKeypress(m_metaState); + + if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) { + c = c & KeyCharacterMap.COMBINING_ACCENT_MASK; + int composed = KeyEvent.getDeadChar(m_lastChar, c); + c = composed; + } + m_lastChar = lc; + if (keyCode != KeyEvent.KEYCODE_BACK) + QtNative.keyDown(keyCode, c, event.getMetaState()); + return true; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) + { + if (!m_started) + return false; + m_metaState = MetaKeyKeyListener.handleKeyUp(m_metaState, keyCode, event); + QtNative.keyUp(keyCode, event.getUnicodeChar(), event.getMetaState()); + return true; + } + + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + } + +/* public boolean onCreateOptionsMenu(Menu menu) + { + QtNative.createOptionsMenu(menu); + try { + return onPrepareOptionsMenu(menu); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public boolean onPrepareOptionsMenu(Menu menu) + { + QtNative.prepareOptionsMenu(menu); + try { + return (Boolean) onPrepareOptionsMenu(menu); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + public boolean onOptionsItemSelected(MenuItem item) + { + return QtNative.optionsItemSelected(item.getGroupId(), item.getItemId()); + }*/ +} diff --git a/tests/auto/android/src/org/qtproject/qt5/android/QtInputConnection.java b/tests/auto/android/src/org/qtproject/qt5/android/QtInputConnection.java new file mode 100644 index 0000000000..e69a03061b --- /dev/null +++ b/tests/auto/android/src/org/qtproject/qt5/android/QtInputConnection.java @@ -0,0 +1,209 @@ +/* + Copyright (c) 2012, BogDan Vatra <bogdan@kde.org> + Contact: http://www.qt-project.org/legal + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package org.qtproject.qt5.android; + +import android.content.Context; +import android.content.Intent; +import android.text.Editable; +import android.text.InputFilter; +import android.util.Log; +import android.view.KeyEvent; +import android.view.View; +import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputMethodManager; + +class QtExtractedText +{ + public int partialEndOffset; + public int partialStartOffset; + public int selectionEnd; + public int selectionStart; + public int startOffset; + public String text; +} + +class QtNativeInputConnection +{ + static native boolean commitText(String text, int newCursorPosition); + static native boolean commitCompletion(String text, int position); + static native boolean deleteSurroundingText(int leftLength, int rightLength); + static native boolean finishComposingText(); + static native int getCursorCapsMode(int reqModes); + static native QtExtractedText getExtractedText(int hintMaxChars, int hintMaxLines, int flags); + static native String getSelectedText(int flags); + static native String getTextAfterCursor(int length, int flags); + static native String getTextBeforeCursor(int length, int flags); + static native boolean setComposingText(String text, int newCursorPosition); + static native boolean setSelection(int start, int end); + static native boolean selectAll(); + static native boolean cut(); + static native boolean copy(); + static native boolean copyURL(); + static native boolean paste(); +} + +public class QtInputConnection extends BaseInputConnection +{ + private static final int ID_SELECT_ALL = android.R.id.selectAll; + private static final int ID_START_SELECTING_TEXT = android.R.id.startSelectingText; + private static final int ID_STOP_SELECTING_TEXT = android.R.id.stopSelectingText; + private static final int ID_CUT = android.R.id.cut; + private static final int ID_COPY = android.R.id.copy; + private static final int ID_PASTE = android.R.id.paste; + private static final int ID_COPY_URL = android.R.id.copyUrl; + 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; + + public QtInputConnection(View targetView) + { + super(targetView, true); + m_view = targetView; + } + + @Override + public boolean beginBatchEdit() + { + return true; + } + + @Override + public boolean endBatchEdit() + { + return true; + } + + @Override + public boolean commitCompletion(CompletionInfo text) + { + return QtNativeInputConnection.commitCompletion(text.getText().toString(), text.getPosition()); + } + + @Override + public boolean commitText(CharSequence text, int newCursorPosition) + { + return QtNativeInputConnection.commitText(text.toString(), newCursorPosition); + } + + @Override + public boolean deleteSurroundingText(int leftLength, int rightLength) + { + return QtNativeInputConnection.deleteSurroundingText(leftLength, rightLength); + } + + @Override + public boolean finishComposingText() + { + return QtNativeInputConnection.finishComposingText(); + } + + @Override + public int getCursorCapsMode(int reqModes) + { + return QtNativeInputConnection.getCursorCapsMode(reqModes); + } + + @Override + public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) + { + QtExtractedText qExtractedText = QtNativeInputConnection.getExtractedText(request.hintMaxChars, request.hintMaxLines, flags); + ExtractedText extractedText = new ExtractedText(); + extractedText.partialEndOffset = qExtractedText.partialEndOffset; + extractedText.partialStartOffset = qExtractedText.partialStartOffset; + extractedText.selectionEnd = qExtractedText.selectionEnd; + extractedText.selectionStart = qExtractedText.selectionStart; + extractedText.startOffset = qExtractedText.startOffset; + extractedText.text = qExtractedText.text; + return extractedText; + } + + public CharSequence getSelectedText(int flags) + { + return QtNativeInputConnection.getSelectedText(flags); + } + + @Override + public CharSequence getTextAfterCursor(int length, int flags) + { + return QtNativeInputConnection.getTextAfterCursor(length, flags); + } + + @Override + public CharSequence getTextBeforeCursor(int length, int flags) + { + return QtNativeInputConnection.getTextBeforeCursor(length, flags); + } + + @Override + public boolean performContextMenuAction(int id) + { + switch (id) { + case ID_SELECT_ALL: + return QtNativeInputConnection.selectAll(); + case ID_COPY: + return QtNativeInputConnection.copy(); + case ID_COPY_URL: + return QtNativeInputConnection.copyURL(); + case ID_CUT: + return QtNativeInputConnection.cut(); + case ID_PASTE: + return QtNativeInputConnection.paste(); + + case ID_SWITCH_INPUT_METHOD: + InputMethodManager imm = (InputMethodManager)m_view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (imm != null) { + imm.showInputMethodPicker(); + } + return true; + + case ID_ADD_TO_DICTIONARY: +// TODO +// String word = m_editable.subSequence(0, m_editable.length()).toString(); +// if (word != null) { +// Intent i = new Intent("com.android.settings.USER_DICTIONARY_INSERT"); +// i.putExtra("word", word); +// i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK); +// m_view.getContext().startActivity(i); +// } + return true; + } + return super.performContextMenuAction(id); + } + + @Override + public boolean setComposingText(CharSequence text, int newCursorPosition) { + return QtNativeInputConnection.setComposingText(text.toString(), newCursorPosition); + } + + @Override + public boolean setSelection(int start, int end) { + return QtNativeInputConnection.setSelection(start, end); + } +} diff --git a/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java b/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java new file mode 100644 index 0000000000..8faeabe5b0 --- /dev/null +++ b/tests/auto/android/src/org/qtproject/qt5/android/QtNative.java @@ -0,0 +1,421 @@ +/* + Copyright (c) 2012, BogDan Vatra <bogdan@kde.org> + Contact: http://www.qt-project.org/legal + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package org.qtproject.qt5.android; + +import java.io.File; +import java.util.ArrayList; + +import android.app.Activity; +import android.app.Application; +import android.content.Intent; +import android.net.Uri; +import android.util.Log; +import android.view.Menu; +import android.view.MotionEvent; + +public class QtNative extends Application +{ + private static QtActivity m_mainActivity = null; + private static QtSurface m_mainView = null; + public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations + + public static final String QtTAG = "Qt JAVA"; // string used for Log.x + private static ArrayList<Runnable> m_lostActions = new ArrayList<Runnable>(); // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.) + private static boolean m_started = false; + private static int m_displayMetricsScreenWidthPixels = 0; + private static int m_displayMetricsScreenHeightPixels = 0; + private static int m_displayMetricsDesktopWidthPixels = 0; + private static int m_displayMetricsDesktopHeightPixels = 0; + private static double m_displayMetricsXDpi = .0; + private static double m_displayMetricsYDpi = .0; + private static int m_oldx, m_oldy; + private static final int m_moveThreshold = 0; + + public static ClassLoader classLoader() + { + return m_mainActivity.getClassLoader(); + } + + public static Activity activity() + { + return m_mainActivity; + } + + public static QtSurface mainView() + { + return m_mainView; + } + + public static void openURL(String url) + { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + activity().startActivity(intent); + } + + // this method loads full path libs + public static void loadQtLibraries(String[] libraries) + { + if (libraries == null) + return; + + for (int i = 0; i < libraries.length; i++) { + try { + File f = new File(libraries[i]); + if (f.exists()) + System.load(libraries[i]); + } catch (SecurityException e) { + Log.i(QtTAG, "Can't load '" + libraries[i] + "'", e); + } catch (Exception e) { + Log.i(QtTAG, "Can't load '" + libraries[i] + "'", e); + } + } + } + + // this method loads bundled libs by name. + public static void loadBundledLibraries(String[] libraries) + { + for (int i = 0; i < libraries.length; i++) { + try { + System.loadLibrary(libraries[i]); + } catch (UnsatisfiedLinkError e) { + Log.i(QtTAG, "Can't load '" + libraries[i] + "'", e); + } catch (SecurityException e) { + Log.i(QtTAG, "Can't load '" + libraries[i] + "'", e); + } catch (Exception e) { + Log.i(QtTAG, "Can't load '" + libraries[i] + "'", e); + } + } + } + + public static void setMainActivity(QtActivity qtMainActivity) + { + synchronized (m_mainActivityMutex) { + m_mainActivity = qtMainActivity; + } + } + public static void setMainView(QtSurface qtSurface) + { + synchronized (m_mainActivityMutex) { + m_mainView = qtSurface; + } + } + + static public ArrayList<Runnable> getLostActions() + { + return m_lostActions; + } + + static public void clearLostActions() + { + m_lostActions.clear(); + } + + private static boolean runAction(Runnable action) + { + synchronized (m_mainActivityMutex) { + if (m_mainActivity == null) + m_lostActions.add(action); + else + m_mainActivity.runOnUiThread(action); + return m_mainActivity != null; + } + } + + public static boolean startApplication(String params, String environment, String mainLibrary, String nativeLibraryDir) throws Exception + { + File f = new File(nativeLibraryDir+"lib"+mainLibrary+".so"); + if (!f.exists()) + throw new Exception("Can't find main library '" + mainLibrary + "'"); + + if (params == null) + params = "-platform\tandroid"; + + boolean res = false; + synchronized (m_mainActivityMutex) { + res = startQtAndroidPlugin(); + setDisplayMetrics(m_displayMetricsScreenWidthPixels, + m_displayMetricsScreenHeightPixels, + m_displayMetricsDesktopWidthPixels, + m_displayMetricsDesktopHeightPixels, + m_displayMetricsXDpi, + m_displayMetricsYDpi); + startQtApplication(f.getAbsolutePath()+"\t"+params, environment); + m_started = true; + } + return res; + } + + public static void setApplicationDisplayMetrics(int screenWidthPixels, + int screenHeightPixels, int desktopWidthPixels, + int desktopHeightPixels, double XDpi, double YDpi) + { + /* Fix buggy dpi report */ + if (XDpi < android.util.DisplayMetrics.DENSITY_LOW) + XDpi = android.util.DisplayMetrics.DENSITY_LOW; + if (YDpi < android.util.DisplayMetrics.DENSITY_LOW) + YDpi = android.util.DisplayMetrics.DENSITY_LOW; + + synchronized (m_mainActivityMutex) { + if (m_started) { + setDisplayMetrics(screenWidthPixels, screenHeightPixels, desktopWidthPixels, desktopHeightPixels, XDpi, YDpi); + } else { + m_displayMetricsScreenWidthPixels = screenWidthPixels; + m_displayMetricsScreenHeightPixels = screenHeightPixels; + m_displayMetricsDesktopWidthPixels = desktopWidthPixels; + m_displayMetricsDesktopHeightPixels = desktopHeightPixels; + m_displayMetricsXDpi = XDpi; + m_displayMetricsYDpi = YDpi; + } + } + } + + public static void pauseApplication() + { + synchronized (m_mainActivityMutex) { + if (m_started) + pauseQtApp(); + } + } + + public static void resumeApplication() + { + synchronized (m_mainActivityMutex) { + if (m_started) { + resumeQtApp(); + updateWindow(); + } + } + } + // application methods + public static native void startQtApplication(String params, String env); + public static native void pauseQtApp(); + public static native void resumeQtApp(); + public static native boolean startQtAndroidPlugin(); + public static native void quitQtAndroidPlugin(); + public static native void terminateQt(); + // application methods + + private static void quitApp() + { + m_mainActivity.finish(); + } + + private static void redrawSurface(final int left, final int top, final int right, final int bottom ) + { + runAction(new Runnable() { + @Override + public void run() { + m_mainActivity.redrawWindow(left, top, right, bottom); + } + }); + } + + @Override + public void onTerminate() + { + if (m_started) + terminateQt(); + super.onTerminate(); + } + + + static public void sendTouchEvent(MotionEvent event, int id) + { + switch (event.getAction()) { + case MotionEvent.ACTION_UP: + mouseUp(id,(int) event.getX(), (int) event.getY()); + break; + + case MotionEvent.ACTION_DOWN: + mouseDown(id,(int) event.getX(), (int) event.getY()); + m_oldx = (int) event.getX(); + m_oldy = (int) event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + int dx = (int) (event.getX() - m_oldx); + int dy = (int) (event.getY() - m_oldy); + if (Math.abs(dx) > m_moveThreshold || Math.abs(dy) > m_moveThreshold) { + mouseMove(id,(int) event.getX(), (int) event.getY()); + m_oldx = (int) event.getX(); + m_oldy = (int) event.getY(); + } + break; + } + } + + static public void sendTrackballEvent(MotionEvent event, int id) + { + switch (event.getAction()) { + case MotionEvent.ACTION_UP: + mouseUp(id, (int) event.getX(), (int) event.getY()); + break; + + case MotionEvent.ACTION_DOWN: + mouseDown(id, (int) event.getX(), (int) event.getY()); + m_oldx = (int) event.getX(); + m_oldy = (int) event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + int dx = (int) (event.getX() - m_oldx); + int dy = (int) (event.getY() - m_oldy); + if (Math.abs(dx) > 5 || Math.abs(dy) > 5) { + mouseMove(id, (int) event.getX(), (int) event.getY()); + m_oldx = (int) event.getX(); + m_oldy = (int) event.getY(); + } + break; + } + } + + + private static void showSoftwareKeyboard(final int x, final int y + , final int width, final int height + , final int inputHints ) + { + runAction(new Runnable() { + @Override + public void run() { + m_mainActivity.showSoftwareKeyboard(); + } + }); + } + + private static void resetSoftwareKeyboard() + { + runAction(new Runnable() { + @Override + public void run() { + m_mainActivity.resetSoftwareKeyboard(); + } + }); + } + + private static void hideSoftwareKeyboard() + { + runAction(new Runnable() { + @Override + public void run() { + m_mainActivity.hideSoftwareKeyboard(); + } + }); + } + + private static void setFullScreen(final boolean fullScreen) + { + runAction(new Runnable() { + @Override + public void run() { + m_mainActivity.setFullScreen(fullScreen); + updateWindow(); + } + }); + } + + // screen methods + public static native void setDisplayMetrics(int screenWidthPixels, + int screenHeightPixels, int desktopWidthPixels, + int desktopHeightPixels, double XDpi, double YDpi); + // screen methods + + private static void showOptionsMenu() + { + runAction(new Runnable() { + @Override + public void run() { + if (m_mainActivity != null) + m_mainActivity.openOptionsMenu(); + } + }); + } + + private static void hideOptionsMenu() + { + runAction(new Runnable() { + @Override + public void run() { + if (m_mainActivity != null) + m_mainActivity.closeOptionsMenu(); + } + }); + } + + private static void showContextMenu() + { + runAction(new Runnable() { + @Override + public void run() { + if (m_mainActivity != null) + m_mainActivity.openContextMenu(m_mainView); + } + }); + } + + private static void hideContextMenu() + { + runAction(new Runnable() { + @Override + public void run() { + if (m_mainActivity != null) + m_mainActivity.closeContextMenu(); + } + }); + } + + // pointer methods + public static native void mouseDown(int winId, int x, int y); + public static native void mouseUp(int winId, int x, int y); + public static native void mouseMove(int winId, int x, int y); + public static native void touchBegin(int winId); + public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float size, float pressure); + public static native void touchEnd(int winId, int action); + // pointer methods + + // keyboard methods + public static native void keyDown(int key, int unicode, int modifier); + public static native void keyUp(int key, int unicode, int modifier); + // keyboard methods + + // surface methods + public static native void destroySurface(); + public static native void setSurface(Object surface); + public static native void lockSurface(); + public static native void unlockSurface(); + // surface methods + + // window methods + public static native void updateWindow(); + // window methods + + // options menu methods + public static native void createOptionsMenu(Menu menu); + public static native boolean prepareOptionsMenu(Menu menu); + public static native boolean optionsItemSelected(int groupId, int itemId); + // options menu methods +} diff --git a/tests/auto/android/src/org/qtproject/qt5/android/QtSurface.java b/tests/auto/android/src/org/qtproject/qt5/android/QtSurface.java new file mode 100644 index 0000000000..7e7db031ec --- /dev/null +++ b/tests/auto/android/src/org/qtproject/qt5/android/QtSurface.java @@ -0,0 +1,163 @@ +/* + Copyright (c) 2012, BogDan Vatra <bogdan@kde.org> + Contact: http://www.qt-project.org/legal + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package org.qtproject.qt5.android; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +public class QtSurface extends SurfaceView implements SurfaceHolder.Callback +{ + private Bitmap m_bitmap=null; + private boolean m_started = false; + private boolean m_usesGL = false; + public QtSurface(Context context, int id) + { + super(context); + setFocusable(true); + getHolder().addCallback(this); + getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU); + setId(id); + } + + public void applicationStarted(boolean usesGL) + { + m_started = true; + m_usesGL = usesGL; + if (getWidth() < 1 || getHeight() < 1) + return; + if (m_usesGL) { + QtNative.setSurface(getHolder().getSurface()); + } else { + QtNative.lockSurface(); + QtNative.setSurface(null); + m_bitmap=Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565); + QtNative.setSurface(m_bitmap); + QtNative.unlockSurface(); + } + } + + @Override + public void surfaceCreated(SurfaceHolder holder) + { + DisplayMetrics metrics = new DisplayMetrics(); + ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics); + QtNative.setApplicationDisplayMetrics(metrics.widthPixels, + metrics.heightPixels, getWidth(), getHeight(), metrics.xdpi, metrics.ydpi); + + if (m_usesGL) + holder.setFormat(PixelFormat.RGBA_8888); + else + holder.setFormat(PixelFormat.RGB_565); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) + { + Log.i(QtNative.QtTAG,"surfaceChanged: "+width+","+height); + if (width < 1 || height < 1) + return; + + DisplayMetrics metrics = new DisplayMetrics(); + ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics); + QtNative.setApplicationDisplayMetrics(metrics.widthPixels, + metrics.heightPixels, width, height, metrics.xdpi, metrics.ydpi); + + if (!m_started) + return; + + if (m_usesGL) { + QtNative.setSurface(holder.getSurface()); + } else { + QtNative.lockSurface(); + QtNative.setSurface(null); + m_bitmap=Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); + QtNative.setSurface(m_bitmap); + QtNative.unlockSurface(); + QtNative.updateWindow(); + } + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) + { + Log.i(QtNative.QtTAG,"surfaceDestroyed "); + if (m_usesGL) { + QtNative.destroySurface(); + } else { + if (!m_started) + return; + + QtNative.lockSurface(); + QtNative.setSurface(null); + QtNative.unlockSurface(); + } + } + + public void drawBitmap(Rect rect) + { + if (!m_started) + return; + QtNative.lockSurface(); + if (null != m_bitmap) { + try { + Canvas cv=getHolder().lockCanvas(rect); + cv.drawBitmap(m_bitmap, rect, rect, null); + getHolder().unlockCanvasAndPost(cv); + } catch (Exception e) { + Log.e(QtNative.QtTAG, "Can't create main activity", e); + } + } + QtNative.unlockSurface(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) + { + if (!m_started) + return false; + QtNative.sendTouchEvent(event, getId()); + return true; + } + + @Override + public boolean onTrackballEvent(MotionEvent event) + { + if (!m_started) + return false; + QtNative.sendTrackballEvent(event, getId()); + return true; + } +} |