Android: support lambda expressions in Java code
use -classpath instead of -bootclasspath param to allow javac to use the default boot class path to support building lambdas, pass the user Android class via -classpath. Task-number: QTBUG-118077 Change-Id: I1ba8274d57e1bd528a1d5b7d779191e7f1412184 Reviewed-by: BogDan Vatra <bogdan@kdab.com> Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
This commit is contained in:
parent
323cf718f6
commit
64fe6d836c
@ -19,7 +19,8 @@ function(qt_internal_add_jar target)
|
|||||||
set(javac_source_version "8")
|
set(javac_source_version "8")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_JAVA_COMPILE_FLAGS -source "${javac_source_version}" -target "${javac_target_version}" -Xlint:unchecked -bootclasspath "${QT_ANDROID_JAR}")
|
set(CMAKE_JAVA_COMPILE_FLAGS -source "${javac_source_version}" -target "${javac_target_version}"
|
||||||
|
-Xlint:unchecked -classpath "${QT_ANDROID_JAR}")
|
||||||
add_jar(${ARGV})
|
add_jar(${ARGV})
|
||||||
|
|
||||||
foreach(f IN LISTS arg_SOURCES)
|
foreach(f IN LISTS arg_SOURCES)
|
||||||
|
@ -63,12 +63,7 @@ public class QtActivityDelegate
|
|||||||
setActionBarVisibility(false);
|
setActionBarVisibility(false);
|
||||||
|
|
||||||
QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
|
QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
|
||||||
new QtInputDelegate.KeyboardVisibilityListener() {
|
() -> m_displayManager.updateFullScreen(m_activity);
|
||||||
@Override
|
|
||||||
public void onKeyboardVisibilityChange() {
|
|
||||||
m_displayManager.updateFullScreen(m_activity);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
|
m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -98,13 +93,10 @@ public class QtActivityDelegate
|
|||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void setSystemUiVisibility(int systemUiVisibility)
|
public void setSystemUiVisibility(int systemUiVisibility)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
m_displayManager.setSystemUiVisibility(m_activity, systemUiVisibility);
|
||||||
public void run() {
|
m_layout.requestLayout();
|
||||||
m_displayManager.setSystemUiVisibility(m_activity, systemUiVisibility);
|
QtNative.updateWindow();
|
||||||
m_layout.requestLayout();
|
|
||||||
QtNative.updateWindow();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,16 +152,13 @@ public class QtActivityDelegate
|
|||||||
if (m_surfaces != null)
|
if (m_surfaces != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Runnable startApplication = new Runnable() {
|
Runnable startApplication = () -> {
|
||||||
@Override
|
try {
|
||||||
public void run() {
|
QtNative.startApplication(appParams, mainLib);
|
||||||
try {
|
m_started = true;
|
||||||
QtNative.startApplication(appParams, mainLib);
|
} catch (Exception e) {
|
||||||
m_started = true;
|
e.printStackTrace();
|
||||||
} catch (Exception e) {
|
m_activity.finish();
|
||||||
e.printStackTrace();
|
|
||||||
m_activity.finish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -224,27 +213,24 @@ public class QtActivityDelegate
|
|||||||
: m_activity.getDisplay().getRefreshRate();
|
: m_activity.getDisplay().getRefreshRate();
|
||||||
QtDisplayManager.handleRefreshRateChanged(refreshRate);
|
QtDisplayManager.handleRefreshRateChanged(refreshRate);
|
||||||
|
|
||||||
m_layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
m_layout.getViewTreeObserver().addOnPreDrawListener(() -> {
|
||||||
@Override
|
if (!m_inputDelegate.isKeyboardVisible())
|
||||||
public boolean onPreDraw() {
|
return true;
|
||||||
if (!m_inputDelegate.isKeyboardVisible())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
Rect r = new Rect();
|
Rect r = new Rect();
|
||||||
m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
|
m_activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
|
||||||
DisplayMetrics metrics = new DisplayMetrics();
|
DisplayMetrics metrics = new DisplayMetrics();
|
||||||
m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||||
final int kbHeight = metrics.heightPixels - r.bottom;
|
final int kbHeight = metrics.heightPixels - r.bottom;
|
||||||
if (kbHeight < 0) {
|
if (kbHeight < 0) {
|
||||||
m_inputDelegate.setKeyboardVisibility(false, System.nanoTime());
|
m_inputDelegate.setKeyboardVisibility(false, System.nanoTime());
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final int[] location = new int[2];
|
|
||||||
m_layout.getLocationOnScreen(location);
|
|
||||||
QtInputDelegate.keyboardGeometryChanged(location[0], r.bottom - location[1],
|
|
||||||
r.width(), kbHeight);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
final int[] location = new int[2];
|
||||||
|
m_layout.getLocationOnScreen(location);
|
||||||
|
QtInputDelegate.keyboardGeometryChanged(location[0], r.bottom - location[1],
|
||||||
|
r.width(), kbHeight);
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout));
|
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout));
|
||||||
}
|
}
|
||||||
@ -256,39 +242,36 @@ public class QtActivityDelegate
|
|||||||
|
|
||||||
public void hideSplashScreen(final int duration)
|
public void hideSplashScreen(final int duration)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_splashScreen == null)
|
||||||
public void run() {
|
return;
|
||||||
if (m_splashScreen == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (duration <= 0) {
|
if (duration <= 0) {
|
||||||
m_layout.removeView(m_splashScreen);
|
m_layout.removeView(m_splashScreen);
|
||||||
m_splashScreen = null;
|
m_splashScreen = null;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Animation fadeOut = new AlphaAnimation(1, 0);
|
||||||
|
fadeOut.setInterpolator(new AccelerateInterpolator());
|
||||||
|
fadeOut.setDuration(duration);
|
||||||
|
|
||||||
|
fadeOut.setAnimationListener(new Animation.AnimationListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animation animation) {
|
||||||
|
hideSplashScreen(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Animation fadeOut = new AlphaAnimation(1, 0);
|
@Override
|
||||||
fadeOut.setInterpolator(new AccelerateInterpolator());
|
public void onAnimationRepeat(Animation animation) {
|
||||||
fadeOut.setDuration(duration);
|
}
|
||||||
|
|
||||||
fadeOut.setAnimationListener(new Animation.AnimationListener() {
|
@Override
|
||||||
@Override
|
public void onAnimationStart(Animation animation) {
|
||||||
public void onAnimationEnd(Animation animation) {
|
}
|
||||||
hideSplashScreen(0);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
m_splashScreen.startAnimation(fadeOut);
|
||||||
public void onAnimationRepeat(Animation animation) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAnimationStart(Animation animation) {
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m_splashScreen.startAnimation(fadeOut);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,13 +325,8 @@ public class QtActivityDelegate
|
|||||||
public void initializeAccessibility()
|
public void initializeAccessibility()
|
||||||
{
|
{
|
||||||
final QtActivityDelegate currentDelegate = this;
|
final QtActivityDelegate currentDelegate = this;
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> m_accessibilityDelegate = new QtAccessibilityDelegate(m_activity,
|
||||||
@Override
|
m_layout, currentDelegate));
|
||||||
public void run() {
|
|
||||||
m_accessibilityDelegate = new QtAccessibilityDelegate(m_activity, m_layout,
|
|
||||||
currentDelegate);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleUiModeChange(int uiMode)
|
void handleUiModeChange(int uiMode)
|
||||||
@ -381,23 +359,13 @@ public class QtActivityDelegate
|
|||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void resetOptionsMenu()
|
public void resetOptionsMenu()
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> m_activity.invalidateOptionsMenu());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
m_activity.invalidateOptionsMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void openOptionsMenu()
|
public void openOptionsMenu()
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> m_activity.openOptionsMenu());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
m_activity.openOptionsMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean m_contextMenuVisible = false;
|
private boolean m_contextMenuVisible = false;
|
||||||
@ -411,38 +379,22 @@ public class QtActivityDelegate
|
|||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void openContextMenu(final int x, final int y, final int w, final int h)
|
public void openContextMenu(final int x, final int y, final int w, final int h)
|
||||||
{
|
{
|
||||||
m_layout.postDelayed(new Runnable() {
|
m_layout.postDelayed(() -> {
|
||||||
@Override
|
m_layout.setLayoutParams(m_inputDelegate.getQtEditText(), new QtLayout.LayoutParams(w, h, x, y), false);
|
||||||
public void run() {
|
PopupMenu popup = new PopupMenu(m_activity, m_inputDelegate.getQtEditText());
|
||||||
m_layout.setLayoutParams(m_inputDelegate.getQtEditText(), new QtLayout.LayoutParams(w, h, x, y), false);
|
QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu());
|
||||||
PopupMenu popup = new PopupMenu(m_activity, m_inputDelegate.getQtEditText());
|
popup.setOnMenuItemClickListener(menuItem ->
|
||||||
QtActivityDelegate.this.onCreatePopupMenu(popup.getMenu());
|
m_activity.onContextItemSelected(menuItem));
|
||||||
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
|
popup.setOnDismissListener(popupMenu ->
|
||||||
@Override
|
m_activity.onContextMenuClosed(popupMenu.getMenu()));
|
||||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
popup.show();
|
||||||
return m_activity.onContextItemSelected(menuItem);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
popup.setOnDismissListener(new PopupMenu.OnDismissListener() {
|
|
||||||
@Override
|
|
||||||
public void onDismiss(PopupMenu popupMenu) {
|
|
||||||
m_activity.onContextMenuClosed(popupMenu.getMenu());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
popup.show();
|
|
||||||
}
|
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void closeContextMenu()
|
public void closeContextMenu()
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> m_activity.closeContextMenu());
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
m_activity.closeContextMenu();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setActionBarVisibility(boolean visible)
|
void setActionBarVisibility(boolean visible)
|
||||||
@ -457,117 +409,104 @@ public class QtActivityDelegate
|
|||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void insertNativeView(int id, View view, int x, int y, int w, int h) {
|
public void insertNativeView(int id, View view, int x, int y, int w, int h) {
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_dummyView != null) {
|
||||||
public void run() {
|
m_layout.removeView(m_dummyView);
|
||||||
if (m_dummyView != null) {
|
m_dummyView = null;
|
||||||
m_layout.removeView(m_dummyView);
|
}
|
||||||
m_dummyView = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_nativeViews.containsKey(id))
|
if (m_nativeViews.containsKey(id))
|
||||||
m_layout.removeView(m_nativeViews.remove(id));
|
m_layout.removeView(m_nativeViews.remove(id));
|
||||||
|
|
||||||
if (w < 0 || h < 0) {
|
if (w < 0 || h < 0) {
|
||||||
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
} else {
|
} else {
|
||||||
view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
view.setId(id);
|
view.setId(id);
|
||||||
m_layout.addView(view);
|
m_layout.addView(view);
|
||||||
m_nativeViews.put(id, view);
|
m_nativeViews.put(id, view);
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth) {
|
public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth) {
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_surfaces.size() == 0) {
|
||||||
public void run() {
|
TypedValue attr = new TypedValue();
|
||||||
if (m_surfaces.size() == 0) {
|
m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, attr, true);
|
||||||
TypedValue attr = new TypedValue();
|
if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT && attr.type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
||||||
m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, attr, true);
|
m_activity.getWindow().setBackgroundDrawable(new ColorDrawable(attr.data));
|
||||||
if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT && attr.type <= TypedValue.TYPE_LAST_COLOR_INT) {
|
|
||||||
m_activity.getWindow().setBackgroundDrawable(new ColorDrawable(attr.data));
|
|
||||||
} else {
|
|
||||||
m_activity.getWindow().setBackgroundDrawable(m_activity.getResources().getDrawable(attr.resourceId, m_activity.getTheme()));
|
|
||||||
}
|
|
||||||
if (m_dummyView != null) {
|
|
||||||
m_layout.removeView(m_dummyView);
|
|
||||||
m_dummyView = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_surfaces.containsKey(id))
|
|
||||||
m_layout.removeView(m_surfaces.remove(id));
|
|
||||||
|
|
||||||
QtSurface surface = new QtSurface(m_activity, id, onTop, imageDepth);
|
|
||||||
if (w < 0 || h < 0) {
|
|
||||||
surface.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
|
||||||
} else {
|
} else {
|
||||||
surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
m_activity.getWindow().setBackgroundDrawable(m_activity.getResources().getDrawable(attr.resourceId, m_activity.getTheme()));
|
||||||
|
}
|
||||||
|
if (m_dummyView != null) {
|
||||||
|
m_layout.removeView(m_dummyView);
|
||||||
|
m_dummyView = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native views are always inserted in the end of the stack (i.e., on top).
|
|
||||||
// All other views are stacked based on the order they are created.
|
|
||||||
final int surfaceCount = getSurfaceCount();
|
|
||||||
m_layout.addView(surface, surfaceCount);
|
|
||||||
|
|
||||||
m_surfaces.put(id, surface);
|
|
||||||
if (!m_splashScreenSticky)
|
|
||||||
hideSplashScreen();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_surfaces.containsKey(id))
|
||||||
|
m_layout.removeView(m_surfaces.remove(id));
|
||||||
|
|
||||||
|
QtSurface surface = new QtSurface(m_activity, id, onTop, imageDepth);
|
||||||
|
if (w < 0 || h < 0) {
|
||||||
|
surface.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
|
} else {
|
||||||
|
surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native views are always inserted in the end of the stack (i.e., on top).
|
||||||
|
// All other views are stacked based on the order they are created.
|
||||||
|
final int surfaceCount = getSurfaceCount();
|
||||||
|
m_layout.addView(surface, surfaceCount);
|
||||||
|
|
||||||
|
m_surfaces.put(id, surface);
|
||||||
|
if (!m_splashScreenSticky)
|
||||||
|
hideSplashScreen();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void setSurfaceGeometry(int id, int x, int y, int w, int h) {
|
public void setSurfaceGeometry(int id, int x, int y, int w, int h) {
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_surfaces.containsKey(id)) {
|
||||||
public void run() {
|
QtSurface surface = m_surfaces.get(id);
|
||||||
if (m_surfaces.containsKey(id)) {
|
surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||||
QtSurface surface = m_surfaces.get(id);
|
} else if (m_nativeViews.containsKey(id)) {
|
||||||
surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
View view = m_nativeViews.get(id);
|
||||||
} else if (m_nativeViews.containsKey(id)) {
|
view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
||||||
View view = m_nativeViews.get(id);
|
} else {
|
||||||
view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
|
Log.e(QtNative.QtTAG, "Surface " + id + " not found!");
|
||||||
} else {
|
|
||||||
Log.e(QtNative.QtTAG, "Surface " + id + " not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void destroySurface(int id) {
|
public void destroySurface(int id) {
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
View view = null;
|
||||||
public void run() {
|
|
||||||
View view = null;
|
|
||||||
|
|
||||||
if (m_surfaces.containsKey(id)) {
|
if (m_surfaces.containsKey(id)) {
|
||||||
view = m_surfaces.remove(id);
|
view = m_surfaces.remove(id);
|
||||||
} else if (m_nativeViews.containsKey(id)) {
|
} else if (m_nativeViews.containsKey(id)) {
|
||||||
view = m_nativeViews.remove(id);
|
view = m_nativeViews.remove(id);
|
||||||
} else {
|
} else {
|
||||||
Log.e(QtNative.QtTAG, "Surface " + id + " not found!");
|
Log.e(QtNative.QtTAG, "Surface " + id + " not found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view == null)
|
if (view == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Keep last frame in stack until it is replaced to get correct
|
// Keep last frame in stack until it is replaced to get correct
|
||||||
// shutdown transition
|
// shutdown transition
|
||||||
if (m_surfaces.size() == 0 && m_nativeViews.size() == 0) {
|
if (m_surfaces.size() == 0 && m_nativeViews.size() == 0) {
|
||||||
m_dummyView = view;
|
m_dummyView = view;
|
||||||
} else {
|
} else {
|
||||||
m_layout.removeView(view);
|
m_layout.removeView(view);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -580,41 +519,35 @@ public class QtActivityDelegate
|
|||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void bringChildToFront(int id)
|
public void bringChildToFront(int id)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
View view = m_surfaces.get(id);
|
||||||
public void run() {
|
if (view != null) {
|
||||||
View view = m_surfaces.get(id);
|
final int surfaceCount = getSurfaceCount();
|
||||||
if (view != null) {
|
if (surfaceCount > 0)
|
||||||
final int surfaceCount = getSurfaceCount();
|
m_layout.moveChild(view, surfaceCount - 1);
|
||||||
if (surfaceCount > 0)
|
return;
|
||||||
m_layout.moveChild(view, surfaceCount - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
view = m_nativeViews.get(id);
|
|
||||||
if (view != null)
|
|
||||||
m_layout.moveChild(view, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
view = m_nativeViews.get(id);
|
||||||
|
if (view != null)
|
||||||
|
m_layout.moveChild(view, -1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void bringChildToBack(int id)
|
public void bringChildToBack(int id)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
View view = m_surfaces.get(id);
|
||||||
public void run() {
|
if (view != null) {
|
||||||
View view = m_surfaces.get(id);
|
m_layout.moveChild(view, 0);
|
||||||
if (view != null) {
|
return;
|
||||||
m_layout.moveChild(view, 0);
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
view = m_nativeViews.get(id);
|
view = m_nativeViews.get(id);
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
final int index = getSurfaceCount();
|
final int index = getSurfaceCount();
|
||||||
m_layout.moveChild(view, index);
|
m_layout.moveChild(view, index);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,7 @@ public class QtActivityLoader extends QtLoader {
|
|||||||
"fatal_error_msg", "string", packageName);
|
"fatal_error_msg", "string", packageName);
|
||||||
errorDialog.setMessage(resources.getString(id));
|
errorDialog.setMessage(resources.getString(id));
|
||||||
errorDialog.setButton(Dialog.BUTTON_POSITIVE, resources.getString(android.R.string.ok),
|
errorDialog.setButton(Dialog.BUTTON_POSITIVE, resources.getString(android.R.string.ok),
|
||||||
new DialogInterface.OnClickListener() {
|
(dialog, which) -> finish());
|
||||||
@Override
|
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
errorDialog.show();
|
errorDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,21 +35,14 @@ public class QtClipboardManager
|
|||||||
{
|
{
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
final Semaphore semaphore = new Semaphore(0);
|
final Semaphore semaphore = new Semaphore(0);
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
m_clipboardManager =
|
||||||
public void run() {
|
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
m_clipboardManager =
|
if (m_clipboardManager != null) {
|
||||||
(ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
|
m_clipboardManager.addPrimaryClipChangedListener(
|
||||||
if (m_clipboardManager != null) {
|
() -> onClipboardDataChanged(m_nativePointer));
|
||||||
m_clipboardManager.addPrimaryClipChangedListener(
|
|
||||||
new ClipboardManager.OnPrimaryClipChangedListener() {
|
|
||||||
public void onPrimaryClipChanged() {
|
|
||||||
onClipboardDataChanged(m_nativePointer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
semaphore.release();
|
|
||||||
}
|
}
|
||||||
|
semaphore.release();
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
|
@ -188,12 +188,9 @@ public class QtInputDelegate {
|
|||||||
{
|
{
|
||||||
if (m_imm == null)
|
if (m_imm == null)
|
||||||
return;
|
return;
|
||||||
m_editText.postDelayed(new Runnable() {
|
m_editText.postDelayed(() -> {
|
||||||
@Override
|
m_imm.restartInput(m_editText);
|
||||||
public void run() {
|
m_editText.m_optionsChanged = false;
|
||||||
m_imm.restartInput(m_editText);
|
|
||||||
m_editText.m_optionsChanged = false;
|
|
||||||
}
|
|
||||||
}, 5);
|
}, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,53 +198,47 @@ public class QtInputDelegate {
|
|||||||
final int x, final int y, final int width, final int height,
|
final int x, final int y, final int width, final int height,
|
||||||
final int inputHints, final int enterKeyType)
|
final int inputHints, final int enterKeyType)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_imm == null)
|
||||||
public void run() {
|
return;
|
||||||
if (m_imm == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (updateSoftInputMode(activity, height))
|
if (updateSoftInputMode(activity, height))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setEditTextOptions(enterKeyType, inputHints);
|
setEditTextOptions(enterKeyType, inputHints);
|
||||||
|
|
||||||
// TODO: The editText is added to the QtLayout, but is it ever removed?
|
// TODO: The editText is added to the QtLayout, but is it ever removed?
|
||||||
QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(width, height, x, y);
|
QtLayout.LayoutParams layoutParams = new QtLayout.LayoutParams(width, height, x, y);
|
||||||
layout.setLayoutParams(m_editText, layoutParams, false);
|
layout.setLayoutParams(m_editText, layoutParams, false);
|
||||||
m_editText.requestFocus();
|
m_editText.requestFocus();
|
||||||
|
|
||||||
m_editText.postDelayed(new Runnable() {
|
m_editText.postDelayed(() -> {
|
||||||
|
m_imm.showSoftInput(m_editText, 0, new ResultReceiver(new Handler()) {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||||
m_imm.showSoftInput(m_editText, 0, new ResultReceiver(new Handler()) {
|
switch (resultCode) {
|
||||||
@Override
|
case InputMethodManager.RESULT_SHOWN:
|
||||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
QtNativeInputConnection.updateCursorPosition();
|
||||||
switch (resultCode) {
|
//FALLTHROUGH
|
||||||
case InputMethodManager.RESULT_SHOWN:
|
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
|
||||||
QtNativeInputConnection.updateCursorPosition();
|
setKeyboardVisibility(true, System.nanoTime());
|
||||||
//FALLTHROUGH
|
if (m_softInputMode == 0) {
|
||||||
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
|
probeForKeyboardHeight(layout, activity,
|
||||||
setKeyboardVisibility(true, System.nanoTime());
|
x, y, width, height, inputHints, enterKeyType);
|
||||||
if (m_softInputMode == 0) {
|
|
||||||
probeForKeyboardHeight(layout, activity,
|
|
||||||
x, y, width, height, inputHints, enterKeyType);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputMethodManager.RESULT_HIDDEN:
|
|
||||||
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
|
|
||||||
setKeyboardVisibility(false, System.nanoTime());
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
});
|
case InputMethodManager.RESULT_HIDDEN:
|
||||||
if (m_editText.m_optionsChanged) {
|
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
|
||||||
m_imm.restartInput(m_editText);
|
setKeyboardVisibility(false, System.nanoTime());
|
||||||
m_editText.m_optionsChanged = false;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 15);
|
});
|
||||||
}
|
if (m_editText.m_optionsChanged) {
|
||||||
|
m_imm.restartInput(m_editText);
|
||||||
|
m_editText.m_optionsChanged = false;
|
||||||
|
}
|
||||||
|
}, 15);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,35 +383,32 @@ public class QtInputDelegate {
|
|||||||
private void probeForKeyboardHeight(QtLayout layout, Activity activity, int x, int y,
|
private void probeForKeyboardHeight(QtLayout layout, Activity activity, int x, int y,
|
||||||
int width, int height, int inputHints, int enterKeyType)
|
int width, int height, int inputHints, int enterKeyType)
|
||||||
{
|
{
|
||||||
layout.postDelayed(new Runnable() {
|
layout.postDelayed(() -> {
|
||||||
@Override
|
if (!m_keyboardIsVisible)
|
||||||
public void run() {
|
return;
|
||||||
if (!m_keyboardIsVisible)
|
DisplayMetrics metrics = new DisplayMetrics();
|
||||||
return;
|
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||||
DisplayMetrics metrics = new DisplayMetrics();
|
Rect r = new Rect();
|
||||||
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
|
||||||
Rect r = new Rect();
|
if (metrics.heightPixels != r.bottom) {
|
||||||
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
|
if (metrics.widthPixels > metrics.heightPixels) { // landscape
|
||||||
if (metrics.heightPixels != r.bottom) {
|
if (m_landscapeKeyboardHeight != r.bottom) {
|
||||||
if (metrics.widthPixels > metrics.heightPixels) { // landscape
|
m_landscapeKeyboardHeight = r.bottom;
|
||||||
if (m_landscapeKeyboardHeight != r.bottom) {
|
showSoftwareKeyboard(activity, layout, x, y, width, height,
|
||||||
m_landscapeKeyboardHeight = r.bottom;
|
inputHints, enterKeyType);
|
||||||
showSoftwareKeyboard(activity, layout, x, y, width, height,
|
|
||||||
inputHints, enterKeyType);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (m_portraitKeyboardHeight != r.bottom) {
|
|
||||||
m_portraitKeyboardHeight = r.bottom;
|
|
||||||
showSoftwareKeyboard(activity, layout, x, y, width, height,
|
|
||||||
inputHints, enterKeyType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// no luck ?
|
if (m_portraitKeyboardHeight != r.bottom) {
|
||||||
// maybe the delay was too short, so let's make it longer
|
m_portraitKeyboardHeight = r.bottom;
|
||||||
if (m_probeKeyboardHeightDelayMs < 1000)
|
showSoftwareKeyboard(activity, layout, x, y, width, height,
|
||||||
m_probeKeyboardHeightDelayMs *= 2;
|
inputHints, enterKeyType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// no luck ?
|
||||||
|
// maybe the delay was too short, so let's make it longer
|
||||||
|
if (m_probeKeyboardHeightDelayMs < 1000)
|
||||||
|
m_probeKeyboardHeightDelayMs *= 2;
|
||||||
}
|
}
|
||||||
}, m_probeKeyboardHeightDelayMs);
|
}, m_probeKeyboardHeightDelayMs);
|
||||||
}
|
}
|
||||||
@ -428,29 +416,26 @@ public class QtInputDelegate {
|
|||||||
public void hideSoftwareKeyboard()
|
public void hideSoftwareKeyboard()
|
||||||
{
|
{
|
||||||
m_isKeyboardHidingAnimationOngoing = true;
|
m_isKeyboardHidingAnimationOngoing = true;
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_imm == null)
|
||||||
public void run() {
|
return;
|
||||||
if (m_imm == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0,
|
m_imm.hideSoftInputFromWindow(m_editText.getWindowToken(), 0,
|
||||||
new ResultReceiver(new Handler()) {
|
new ResultReceiver(new Handler()) {
|
||||||
@Override
|
@Override
|
||||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||||
switch (resultCode) {
|
switch (resultCode) {
|
||||||
case InputMethodManager.RESULT_SHOWN:
|
case InputMethodManager.RESULT_SHOWN:
|
||||||
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
|
case InputMethodManager.RESULT_UNCHANGED_SHOWN:
|
||||||
setKeyboardVisibility(true, System.nanoTime());
|
setKeyboardVisibility(true, System.nanoTime());
|
||||||
break;
|
break;
|
||||||
case InputMethodManager.RESULT_HIDDEN:
|
case InputMethodManager.RESULT_HIDDEN:
|
||||||
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
|
case InputMethodManager.RESULT_UNCHANGED_HIDDEN:
|
||||||
setKeyboardVisibility(false, System.nanoTime());
|
setKeyboardVisibility(false, System.nanoTime());
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,14 +443,11 @@ public class QtInputDelegate {
|
|||||||
public void updateSelection(final int selStart, final int selEnd,
|
public void updateSelection(final int selStart, final int selEnd,
|
||||||
final int candidatesStart, final int candidatesEnd)
|
final int candidatesStart, final int candidatesEnd)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_imm == null)
|
||||||
public void run() {
|
return;
|
||||||
if (m_imm == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_imm.updateSelection(m_editText, selStart, selEnd, candidatesStart, candidatesEnd);
|
m_imm.updateSelection(m_editText, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,13 +472,8 @@ public class QtInputDelegate {
|
|||||||
int editX, int editY, int editButtons,
|
int editX, int editY, int editButtons,
|
||||||
int x1, int y1, int x2, int y2, boolean rtl)
|
int x1, int y1, int x2, int y2, boolean rtl)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> updateHandleImpl(activity, layout, mode, editX, editY, editButtons,
|
||||||
@Override
|
x1, y1, x2, y2, rtl));
|
||||||
public void run() {
|
|
||||||
updateHandleImpl(activity, layout, mode, editX, editY, editButtons,
|
|
||||||
x1, y1, x2, y2, rtl);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateHandleImpl(Activity activity, QtLayout layout, int mode,
|
private void updateHandleImpl(Activity activity, QtLayout layout, int mode,
|
||||||
|
@ -462,13 +462,10 @@ public abstract class QtLoader {
|
|||||||
ArrayList<String> oneEntryArray = new ArrayList<>(Collections.singletonList(mainLibName));
|
ArrayList<String> oneEntryArray = new ArrayList<>(Collections.singletonList(mainLibName));
|
||||||
String mainLibPath = getLibrariesFullPaths(oneEntryArray).get(0);
|
String mainLibPath = getLibrariesFullPaths(oneEntryArray).get(0);
|
||||||
final boolean[] success = {true};
|
final boolean[] success = {true};
|
||||||
QtNative.getQtThread().run(new Runnable() {
|
QtNative.getQtThread().run(() -> {
|
||||||
@Override
|
m_mainLib = loadLibraryHelper(mainLibPath);
|
||||||
public void run() {
|
if (m_mainLib == null)
|
||||||
m_mainLib = loadLibraryHelper(mainLibPath);
|
success[0] = false;
|
||||||
if (m_mainLib == null)
|
|
||||||
success[0] = false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return success[0];
|
return success[0];
|
||||||
@ -488,15 +485,12 @@ public abstract class QtLoader {
|
|||||||
ArrayList<String> fullPathLibs = getLibrariesFullPaths(libraries);
|
ArrayList<String> fullPathLibs = getLibrariesFullPaths(libraries);
|
||||||
|
|
||||||
final boolean[] success = {true};
|
final boolean[] success = {true};
|
||||||
QtNative.getQtThread().run(new Runnable() {
|
QtNative.getQtThread().run(() -> {
|
||||||
@Override
|
for (int i = 0; i < fullPathLibs.size(); ++i) {
|
||||||
public void run() {
|
String libName = fullPathLibs.get(i);
|
||||||
for (int i = 0; i < fullPathLibs.size(); ++i) {
|
if (loadLibraryHelper(libName) == null) {
|
||||||
String libName = fullPathLibs.get(i);
|
success[0] = false;
|
||||||
if (loadLibraryHelper(libName) == null) {
|
break;
|
||||||
success[0] = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -159,177 +159,163 @@ public class QtMessageDialogHelper
|
|||||||
public void show(long handler)
|
public void show(long handler)
|
||||||
{
|
{
|
||||||
m_handler = handler;
|
m_handler = handler;
|
||||||
m_activity.runOnUiThread( new Runnable() {
|
m_activity.runOnUiThread(() -> {
|
||||||
@Override
|
if (m_dialog != null && m_dialog.isShowing())
|
||||||
public void run() {
|
m_dialog.dismiss();
|
||||||
if (m_dialog != null && m_dialog.isShowing())
|
|
||||||
m_dialog.dismiss();
|
|
||||||
|
|
||||||
m_dialog = new AlertDialog.Builder(m_activity).create();
|
m_dialog = new AlertDialog.Builder(m_activity).create();
|
||||||
m_theme = m_dialog.getWindow().getContext().getTheme();
|
m_theme = m_dialog.getWindow().getContext().getTheme();
|
||||||
|
|
||||||
if (m_title != null)
|
if (m_title != null)
|
||||||
m_dialog.setTitle(m_title);
|
m_dialog.setTitle(m_title);
|
||||||
m_dialog.setOnCancelListener( new DialogInterface.OnCancelListener() {
|
m_dialog.setOnCancelListener(dialogInterface -> QtNativeDialogHelper.dialogResult(handler(), -1));
|
||||||
@Override
|
m_dialog.setCancelable(m_buttonsList == null);
|
||||||
public void onCancel(DialogInterface dialogInterface) {
|
m_dialog.setCanceledOnTouchOutside(m_buttonsList == null);
|
||||||
QtNativeDialogHelper.dialogResult(handler(), -1);
|
m_dialog.setIcon(getIconDrawable());
|
||||||
}
|
ScrollView scrollView = new ScrollView(m_activity);
|
||||||
});
|
RelativeLayout dialogLayout = new RelativeLayout(m_activity);
|
||||||
m_dialog.setCancelable(m_buttonsList == null);
|
int id = 1;
|
||||||
m_dialog.setCanceledOnTouchOutside(m_buttonsList == null);
|
View lastView = null;
|
||||||
m_dialog.setIcon(getIconDrawable());
|
View.OnLongClickListener copyText = view -> {
|
||||||
ScrollView scrollView = new ScrollView(m_activity);
|
TextView tv = (TextView)view;
|
||||||
RelativeLayout dialogLayout = new RelativeLayout(m_activity);
|
if (tv != null) {
|
||||||
int id = 1;
|
ClipboardManager cm = (ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
View lastView = null;
|
cm.setText(tv.getText());
|
||||||
View.OnLongClickListener copyText = new View.OnLongClickListener() {
|
}
|
||||||
@Override
|
return true;
|
||||||
public boolean onLongClick(View view) {
|
};
|
||||||
TextView tv = (TextView)view;
|
if (m_text != null)
|
||||||
if (tv != null) {
|
{
|
||||||
ClipboardManager cm = (android.text.ClipboardManager) m_activity.getSystemService(Context.CLIPBOARD_SERVICE);
|
TextView view = new TextView(m_activity);
|
||||||
cm.setText(tv.getText());
|
view.setId(id++);
|
||||||
}
|
view.setOnLongClickListener(copyText);
|
||||||
return true;
|
view.setLongClickable(true);
|
||||||
}
|
|
||||||
};
|
|
||||||
if (m_text != null)
|
|
||||||
{
|
|
||||||
TextView view = new TextView(m_activity);
|
|
||||||
view.setId(id++);
|
|
||||||
view.setOnLongClickListener(copyText);
|
|
||||||
view.setLongClickable(true);
|
|
||||||
|
|
||||||
view.setText(m_text);
|
view.setText(m_text);
|
||||||
view.setTextAppearance(m_activity, android.R.style.TextAppearance_Medium);
|
view.setTextAppearance(m_activity, android.R.style.TextAppearance_Medium);
|
||||||
|
|
||||||
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
RelativeLayout.LayoutParams layout = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||||
layout.setMargins(16, 8, 16, 8);
|
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);
|
||||||
|
view.setTextAppearance(m_activity, android.R.style.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);
|
layout.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||||
dialogLayout.addView(view, layout);
|
dialogLayout.addView(view, layout);
|
||||||
lastView = view;
|
lastView = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_informativeText != null)
|
if (m_detailedText != null)
|
||||||
|
{
|
||||||
|
TextView view= new TextView(m_activity);
|
||||||
|
view.setId(id++);
|
||||||
|
view.setOnLongClickListener(copyText);
|
||||||
|
view.setLongClickable(true);
|
||||||
|
|
||||||
|
view.setText(m_detailedText);
|
||||||
|
view.setTextAppearance(m_activity, android.R.style.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)
|
||||||
{
|
{
|
||||||
TextView view= new TextView(m_activity);
|
Button bv;
|
||||||
view.setId(id++);
|
|
||||||
view.setOnLongClickListener(copyText);
|
|
||||||
view.setLongClickable(true);
|
|
||||||
|
|
||||||
view.setText(m_informativeText);
|
|
||||||
view.setTextAppearance(m_activity, android.R.style.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);
|
|
||||||
view.setTextAppearance(m_activity, android.R.style.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;
|
|
||||||
try {
|
|
||||||
bv = new Button(m_activity, null, Class.forName("android.R$attr").getDeclaredField("borderlessButtonStyle").getInt(null));
|
|
||||||
} catch (Exception e) {
|
|
||||||
bv = new Button(m_activity);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
bv.setText(button.m_text);
|
|
||||||
bv.setOnClickListener(button);
|
|
||||||
if (!firstButton) // first button
|
|
||||||
{
|
|
||||||
View spacer = new View(m_activity);
|
|
||||||
try {
|
|
||||||
LinearLayout.LayoutParams 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 = new LinearLayout.LayoutParams(
|
|
||||||
RelativeLayout.LayoutParams.MATCH_PARENT,
|
|
||||||
RelativeLayout.LayoutParams.WRAP_CONTENT, 1.0f);
|
|
||||||
buttonsLayout.addView(bv, layout);
|
|
||||||
firstButton = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
View horizontalDevider = new View(m_activity);
|
bv = new Button(m_activity, null, Class.forName("android.R$attr").getDeclaredField("borderlessButtonStyle").getInt(null));
|
||||||
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) {
|
} catch (Exception e) {
|
||||||
|
bv = new Button(m_activity);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
|
||||||
|
bv.setText(button.m_text);
|
||||||
|
bv.setOnClickListener(button);
|
||||||
|
if (!firstButton) // first button
|
||||||
|
{
|
||||||
|
View spacer = new View(m_activity);
|
||||||
|
try {
|
||||||
|
LinearLayout.LayoutParams 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 = new LinearLayout.LayoutParams(
|
||||||
|
RelativeLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
RelativeLayout.LayoutParams.WRAP_CONTENT, 1.0f);
|
||||||
|
buttonsLayout.addView(bv, layout);
|
||||||
|
firstButton = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (lastView != null) {
|
||||||
relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
|
relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||||
relativeParams.setMargins(2, 0, 2, 0);
|
dialogLayout.addView(horizontalDevider, relativeParams);
|
||||||
dialogLayout.addView(buttonsLayout, relativeParams);
|
lastView = horizontalDevider;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
scrollView.addView(dialogLayout);
|
RelativeLayout.LayoutParams relativeParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
|
||||||
m_dialog.setView(scrollView);
|
if (lastView != null) {
|
||||||
m_dialog.show();
|
relativeParams.addRule(RelativeLayout.BELOW, lastView.getId());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
relativeParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||||
|
relativeParams.setMargins(2, 0, 2, 0);
|
||||||
|
dialogLayout.addView(buttonsLayout, relativeParams);
|
||||||
}
|
}
|
||||||
|
scrollView.addView(dialogLayout);
|
||||||
|
m_dialog.setView(scrollView);
|
||||||
|
m_dialog.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
public void hide()
|
public void hide()
|
||||||
{
|
{
|
||||||
m_activity.runOnUiThread( new Runnable() {
|
m_activity.runOnUiThread(() -> {
|
||||||
@Override
|
if (m_dialog != null && m_dialog.isShowing())
|
||||||
public void run() {
|
m_dialog.dismiss();
|
||||||
if (m_dialog != null && m_dialog.isShowing())
|
reset();
|
||||||
m_dialog.dismiss();
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,12 +46,7 @@ public class QtNative
|
|||||||
private static final QtThread m_qtThread = new QtThread();
|
private static final QtThread m_qtThread = new QtThread();
|
||||||
private static ClassLoader m_classLoader = null;
|
private static ClassLoader m_classLoader = null;
|
||||||
|
|
||||||
private static final Runnable runPendingCppRunnablesRunnable = new Runnable() {
|
private static final Runnable runPendingCppRunnablesRunnable = QtNative::runPendingCppRunnables;
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
runPendingCppRunnables();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static boolean isStarted()
|
public static boolean isStarted()
|
||||||
{
|
{
|
||||||
@ -255,12 +250,7 @@ public class QtNative
|
|||||||
@UsedFromNativeCode
|
@UsedFromNativeCode
|
||||||
private static void setViewVisibility(final View view, final boolean visible)
|
private static void setViewVisibility(final View view, final boolean visible)
|
||||||
{
|
{
|
||||||
runAction(new Runnable() {
|
runAction(() -> view.setVisibility(visible ? View.VISIBLE : View.GONE));
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
view.setVisibility(visible ? View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean startApplication(ArrayList<String> params, String mainLib)
|
public static boolean startApplication(ArrayList<String> params, String mainLib)
|
||||||
@ -269,18 +259,8 @@ public class QtNative
|
|||||||
synchronized (m_mainActivityMutex) {
|
synchronized (m_mainActivityMutex) {
|
||||||
String paramsStr = String.join("\t", params);
|
String paramsStr = String.join("\t", params);
|
||||||
final String qtParams = mainLib + "\t" + paramsStr;
|
final String qtParams = mainLib + "\t" + paramsStr;
|
||||||
m_qtThread.run(new Runnable() {
|
m_qtThread.run(() -> res[0] = startQtAndroidPlugin(qtParams));
|
||||||
@Override
|
m_qtThread.post(QtNative::startQtApplication);
|
||||||
public void run() {
|
|
||||||
res[0] = startQtAndroidPlugin(qtParams);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
m_qtThread.post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
startQtApplication();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
waitForServiceSetup();
|
waitForServiceSetup();
|
||||||
m_started = true;
|
m_started = true;
|
||||||
}
|
}
|
||||||
@ -289,17 +269,14 @@ public class QtNative
|
|||||||
|
|
||||||
public static void quitApp()
|
public static void quitApp()
|
||||||
{
|
{
|
||||||
runAction(new Runnable() {
|
runAction(() -> {
|
||||||
@Override
|
quitQtAndroidPlugin();
|
||||||
public void run() {
|
if (isActivityValid())
|
||||||
quitQtAndroidPlugin();
|
m_activity.get().finish();
|
||||||
if (isActivityValid())
|
if (isServiceValid())
|
||||||
m_activity.get().finish();
|
m_service.get().stopSelf();
|
||||||
if (isServiceValid())
|
|
||||||
m_service.get().stopSelf();
|
|
||||||
|
|
||||||
m_started = false;
|
m_started = false;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +45,9 @@ public class QtThread {
|
|||||||
public void run(final Runnable runnable) {
|
public void run(final Runnable runnable) {
|
||||||
final Semaphore sem = new Semaphore(0);
|
final Semaphore sem = new Semaphore(0);
|
||||||
synchronized (m_qtThread) {
|
synchronized (m_qtThread) {
|
||||||
m_pendingRunnables.add(new Runnable() {
|
m_pendingRunnables.add(() -> {
|
||||||
@Override
|
runnable.run();
|
||||||
public void run() {
|
sem.release();
|
||||||
runnable.run();
|
|
||||||
sem.release();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
m_qtThread.notify();
|
m_qtThread.notify();
|
||||||
}
|
}
|
||||||
|
@ -161,99 +161,83 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate
|
|||||||
|
|
||||||
public void notifyScrolledEvent(int viewId)
|
public void notifyScrolledEvent(int viewId)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> sendEventForVirtualViewId(viewId,
|
||||||
@Override
|
AccessibilityEvent.TYPE_VIEW_SCROLLED));
|
||||||
public void run() {
|
|
||||||
sendEventForVirtualViewId(viewId, AccessibilityEvent.TYPE_VIEW_SCROLLED);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyLocationChange(int viewId)
|
public void notifyLocationChange(int viewId)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_focusedVirtualViewId == viewId)
|
||||||
public void run() {
|
invalidateVirtualViewId(m_focusedVirtualViewId);
|
||||||
if (m_focusedVirtualViewId == viewId)
|
|
||||||
invalidateVirtualViewId(m_focusedVirtualViewId);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyObjectHide(int viewId, int parentId)
|
public void notifyObjectHide(int viewId, int parentId)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
// If the object had accessibility focus, we need to clear it.
|
||||||
public void run() {
|
// Note: This code is mostly copied from
|
||||||
// If the object had accessibility focus, we need to clear it.
|
// AccessibilityNodeProvider::performAction, but we remove the
|
||||||
// Note: This code is mostly copied from
|
// focus only if the focused view id matches the one that was hidden.
|
||||||
// AccessibilityNodeProvider::performAction, but we remove the
|
if (m_focusedVirtualViewId == viewId) {
|
||||||
// focus only if the focused view id matches the one that was hidden.
|
m_focusedVirtualViewId = INVALID_ID;
|
||||||
if (m_focusedVirtualViewId == viewId) {
|
m_view.invalidate();
|
||||||
m_focusedVirtualViewId = INVALID_ID;
|
sendEventForVirtualViewId(viewId,
|
||||||
m_view.invalidate();
|
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
|
||||||
sendEventForVirtualViewId(viewId,
|
|
||||||
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
|
|
||||||
}
|
|
||||||
// When the object is hidden, we need to notify its parent about
|
|
||||||
// content change, not the hidden object itself
|
|
||||||
invalidateVirtualViewId(parentId);
|
|
||||||
}
|
}
|
||||||
|
// When the object is hidden, we need to notify its parent about
|
||||||
|
// content change, not the hidden object itself
|
||||||
|
invalidateVirtualViewId(parentId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyObjectFocus(int viewId)
|
public void notifyObjectFocus(int viewId)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
if (m_view == null)
|
||||||
public void run() {
|
return;
|
||||||
if (m_view == null)
|
m_focusedVirtualViewId = viewId;
|
||||||
return;
|
m_view.invalidate();
|
||||||
m_focusedVirtualViewId = viewId;
|
sendEventForVirtualViewId(viewId,
|
||||||
m_view.invalidate();
|
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
||||||
sendEventForVirtualViewId(viewId,
|
|
||||||
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyValueChanged(int viewId, String value)
|
public void notifyValueChanged(int viewId, String value)
|
||||||
{
|
{
|
||||||
QtNative.runAction(new Runnable() {
|
QtNative.runAction(() -> {
|
||||||
@Override
|
// Send a TYPE_ANNOUNCEMENT event with the new value
|
||||||
public void run() {
|
|
||||||
// Send a TYPE_ANNOUNCEMENT event with the new value
|
|
||||||
|
|
||||||
if ((viewId == INVALID_ID) || !m_manager.isEnabled()) {
|
if ((viewId == INVALID_ID) || !m_manager.isEnabled()) {
|
||||||
Log.w(TAG, "notifyValueChanged() for invalid view");
|
Log.w(TAG, "notifyValueChanged() for invalid view");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
final ViewGroup group = (ViewGroup) m_view.getParent();
|
|
||||||
if (group == null) {
|
|
||||||
Log.w(TAG, "Could not announce value because ViewGroup was null.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final AccessibilityEvent event =
|
|
||||||
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
|
||||||
|
|
||||||
event.setEnabled(true);
|
|
||||||
event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME);
|
|
||||||
|
|
||||||
event.setContentDescription(value);
|
|
||||||
|
|
||||||
if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) {
|
|
||||||
Log.w(TAG, "No value to announce for " + event.getClassName());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
event.setPackageName(m_view.getContext().getPackageName());
|
|
||||||
event.setSource(m_view, viewId);
|
|
||||||
|
|
||||||
if (!group.requestSendAccessibilityEvent(m_view, event))
|
|
||||||
Log.w(TAG, "Failed to send value change announcement for " + event.getClassName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final ViewGroup group = (ViewGroup) m_view.getParent();
|
||||||
|
if (group == null) {
|
||||||
|
Log.w(TAG, "Could not announce value because ViewGroup was null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AccessibilityEvent event =
|
||||||
|
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_ANNOUNCEMENT);
|
||||||
|
|
||||||
|
event.setEnabled(true);
|
||||||
|
event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME);
|
||||||
|
|
||||||
|
event.setContentDescription(value);
|
||||||
|
|
||||||
|
if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) {
|
||||||
|
Log.w(TAG, "No value to announce for " + event.getClassName());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setPackageName(m_view.getContext().getPackageName());
|
||||||
|
event.setSource(m_view, viewId);
|
||||||
|
|
||||||
|
if (!group.requestSendAccessibilityEvent(m_view, event))
|
||||||
|
Log.w(TAG, "Failed to send value change announcement for " + event.getClassName());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user