Android: make QtActivityDelegate practically NonNull
To avoid any potential null access on the delegate from various paths like onResume(), onPause(), etc. where the delegate or some of its member or delegates might also be null, make it final and assign it a default instance in the Activity constructor. This applies the same way for QtDisplayManager and QtInputDelegate, which are final and assigned an instance at the QtActivityDelegate constructor. This means also, that each of those delegates or classes should ensure any of objects used under them are safely called or not in null cases. This should help us reduce the amount of potential NullPointerExceptions. Fixes: QTBUG-129704 Change-Id: I36861c95d3b389fd88822aac0ae3616ccb3e304d Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io> (cherry picked from commit 64f152d52a8720de71c7440ca2979345b919c58c) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
7338e481a9
commit
f7aadf60de
@ -32,7 +32,7 @@ public class QtActivityBase extends Activity
|
||||
private boolean m_retainNonConfigurationInstance = false;
|
||||
private Configuration m_prevConfig;
|
||||
|
||||
private QtActivityDelegate m_delegate;
|
||||
private final QtActivityDelegate m_delegate;
|
||||
|
||||
public static final String EXTRA_SOURCE_INFO = "org.qtproject.qt.android.sourceInfo";
|
||||
|
||||
@ -83,6 +83,11 @@ public class QtActivityBase extends Activity
|
||||
Runtime.getRuntime().exit(0);
|
||||
}
|
||||
|
||||
public QtActivityBase()
|
||||
{
|
||||
m_delegate = new QtActivityDelegate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
@ -102,8 +107,6 @@ public class QtActivityBase extends Activity
|
||||
restartApplication();
|
||||
}
|
||||
|
||||
m_delegate = new QtActivityDelegate(this);
|
||||
|
||||
QtNative.registerAppStateListener(m_delegate);
|
||||
|
||||
addReferrer(getIntent());
|
||||
|
@ -48,7 +48,12 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
QtActivityDelegate(Activity activity)
|
||||
{
|
||||
super(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
void initMembers()
|
||||
{
|
||||
super.initMembers();
|
||||
setActionBarVisibility(false);
|
||||
setActivityBackgroundDrawable();
|
||||
}
|
||||
@ -82,10 +87,15 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
public void setSystemUiVisibility(int systemUiVisibility)
|
||||
{
|
||||
if (m_layout == null)
|
||||
return;
|
||||
|
||||
QtNative.runAction(() -> {
|
||||
m_displayManager.setSystemUiVisibility(systemUiVisibility);
|
||||
m_layout.requestLayout();
|
||||
QtNative.updateWindow();
|
||||
if (m_layout != null) {
|
||||
m_displayManager.setSystemUiVisibility(systemUiVisibility);
|
||||
m_layout.requestLayout();
|
||||
QtNative.updateWindow();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -101,12 +111,19 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
void startNativeApplicationImpl(String appParams, String mainLib)
|
||||
{
|
||||
if (m_layout == null) {
|
||||
Log.e(QtTAG, "Unable to start native application with a null layout");
|
||||
return;
|
||||
}
|
||||
|
||||
m_layout.getViewTreeObserver().addOnGlobalLayoutListener(
|
||||
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
QtNative.startApplication(appParams, mainLib);
|
||||
m_layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
if (m_layout != null) {
|
||||
QtNative.startApplication(appParams, mainLib);
|
||||
m_layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -114,9 +131,11 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
protected void setUpLayout()
|
||||
{
|
||||
int orientation = m_activity.getResources().getConfiguration().orientation;
|
||||
// This should be assigned only once, otherwise, we'd have to check
|
||||
// for null everywhere including before and inside runAction() Runnables.
|
||||
m_layout = new QtRootLayout(m_activity);
|
||||
|
||||
int orientation = m_activity.getResources().getConfiguration().orientation;
|
||||
setUpSplashScreen(orientation);
|
||||
m_activity.registerForContextMenu(m_layout);
|
||||
m_activity.setContentView(m_layout,
|
||||
@ -155,6 +174,11 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
protected void setUpSplashScreen(int orientation)
|
||||
{
|
||||
if (m_layout == null) {
|
||||
Log.e(QtTAG, "Unable to setup splash screen with a null layout");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ActivityInfo info = m_activity.getPackageManager().getActivityInfo(
|
||||
m_activity.getComponentName(),
|
||||
@ -192,7 +216,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
if (m_splashScreen == null)
|
||||
return;
|
||||
|
||||
if (duration <= 0) {
|
||||
if (m_layout != null && duration <= 0) {
|
||||
m_layout.removeView(m_splashScreen);
|
||||
m_splashScreen = null;
|
||||
return;
|
||||
@ -303,7 +327,16 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
public void openContextMenu(final int x, final int y, final int w, final int h)
|
||||
{
|
||||
if (m_layout == null) {
|
||||
Log.e(QtTAG, "Unable to open context menu with a null layout");
|
||||
return;
|
||||
}
|
||||
|
||||
m_layout.postDelayed(() -> {
|
||||
if (m_layout == null) {
|
||||
Log.w(QtTAG, "Unable to open context menu on null layout");
|
||||
return;
|
||||
}
|
||||
final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText();
|
||||
if (focusedEditText == null) {
|
||||
Log.w(QtTAG, "No focused view when trying to open context menu");
|
||||
@ -350,10 +383,13 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
public void addTopLevelWindow(final QtWindow window)
|
||||
{
|
||||
if (window == null)
|
||||
if (m_layout == null || window == null)
|
||||
return;
|
||||
|
||||
QtNative.runAction(()-> {
|
||||
if (m_layout == null)
|
||||
return;
|
||||
|
||||
if (m_topLevelWindows.size() == 0) {
|
||||
if (m_dummyView != null) {
|
||||
m_layout.removeView(m_dummyView);
|
||||
@ -379,7 +415,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
// Keep last frame in stack until it is replaced to get correct
|
||||
// shutdown transition
|
||||
m_dummyView = window;
|
||||
} else {
|
||||
} else if (m_layout != null) {
|
||||
m_layout.removeView(window);
|
||||
}
|
||||
}
|
||||
@ -390,22 +426,26 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@Override
|
||||
public void bringChildToFront(final int id)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
QtWindow window = m_topLevelWindows.get(id);
|
||||
if (window != null)
|
||||
m_layout.moveChild(window, m_topLevelWindows.size() - 1);
|
||||
});
|
||||
if (m_layout != null) {
|
||||
QtNative.runAction(() -> {
|
||||
QtWindow window = m_topLevelWindows.get(id);
|
||||
if (window != null && m_layout != null)
|
||||
m_layout.moveChild(window, m_topLevelWindows.size() - 1);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@UsedFromNativeCode
|
||||
@Override
|
||||
public void bringChildToBack(int id)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
QtWindow window = m_topLevelWindows.get(id);
|
||||
if (window != null)
|
||||
m_layout.moveChild(window, 0);
|
||||
});
|
||||
if (m_layout != null) {
|
||||
QtNative.runAction(() -> {
|
||||
QtWindow window = m_topLevelWindows.get(id);
|
||||
if (window != null && m_layout != null)
|
||||
m_layout.moveChild(window, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void setActivityBackgroundDrawable()
|
||||
@ -429,6 +469,9 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
@UsedFromNativeCode
|
||||
void insertNativeView(int id, View view, int x, int y, int w, int h)
|
||||
{
|
||||
if (m_layout == null)
|
||||
return;
|
||||
|
||||
QtNative.runAction(()-> {
|
||||
if (m_dummyView != null) {
|
||||
m_layout.removeView(m_dummyView);
|
||||
|
@ -31,14 +31,16 @@ import android.view.WindowInsetsController;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import org.qtproject.qt.android.QtInputDelegate.KeyboardVisibilityListener;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
abstract class QtActivityDelegateBase
|
||||
{
|
||||
protected Activity m_activity;
|
||||
protected HashMap<Integer, QtWindow> m_topLevelWindows;
|
||||
protected QtDisplayManager m_displayManager = null;
|
||||
protected QtInputDelegate m_inputDelegate = null;
|
||||
protected final Activity m_activity;
|
||||
protected final HashMap<Integer, QtWindow> m_topLevelWindows = new HashMap<>();
|
||||
protected final QtDisplayManager m_displayManager;
|
||||
protected final QtInputDelegate m_inputDelegate;
|
||||
|
||||
private boolean m_membersInitialized = false;
|
||||
private boolean m_contextMenuVisible = false;
|
||||
@ -55,8 +57,9 @@ abstract class QtActivityDelegateBase
|
||||
QtActivityDelegateBase(Activity activity)
|
||||
{
|
||||
m_activity = activity;
|
||||
// Set native context
|
||||
QtNative.setActivity(m_activity);
|
||||
m_displayManager = new QtDisplayManager(m_activity);
|
||||
m_inputDelegate = new QtInputDelegate(m_displayManager::updateFullScreen);
|
||||
}
|
||||
|
||||
QtDisplayManager displayManager() {
|
||||
@ -88,14 +91,9 @@ abstract class QtActivityDelegateBase
|
||||
void initMembers()
|
||||
{
|
||||
m_membersInitialized = true;
|
||||
m_topLevelWindows = new HashMap<Integer, QtWindow>();
|
||||
|
||||
m_displayManager = new QtDisplayManager(m_activity);
|
||||
m_topLevelWindows.clear();
|
||||
m_displayManager.registerDisplayListener();
|
||||
|
||||
QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
|
||||
() -> m_displayManager.updateFullScreen();
|
||||
m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
|
||||
m_inputDelegate.initInputMethodManager(m_activity);
|
||||
|
||||
try {
|
||||
PackageManager pm = m_activity.getPackageManager();
|
||||
|
@ -46,16 +46,12 @@ class QtDisplayManager {
|
||||
|
||||
private static int m_previousRotation = -1;
|
||||
|
||||
private DisplayManager.DisplayListener m_displayListener = null;
|
||||
private final DisplayManager.DisplayListener m_displayListener;
|
||||
private final Activity m_activity;
|
||||
|
||||
QtDisplayManager(Activity activity)
|
||||
{
|
||||
m_activity = activity;
|
||||
initDisplayListener();
|
||||
}
|
||||
|
||||
private void initDisplayListener() {
|
||||
m_displayListener = new DisplayManager.DisplayListener() {
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) {
|
||||
|
@ -43,7 +43,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
// handle methods
|
||||
|
||||
private QtEditText m_currentEditText = null;
|
||||
private final InputMethodManager m_imm;
|
||||
private InputMethodManager m_imm;
|
||||
|
||||
private boolean m_keyboardIsVisible = false;
|
||||
private boolean m_isKeyboardHidingAnimationOngoing = false;
|
||||
@ -72,9 +72,13 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
|
||||
private final KeyboardVisibilityListener m_keyboardVisibilityListener;
|
||||
|
||||
QtInputDelegate(Activity activity, KeyboardVisibilityListener listener)
|
||||
QtInputDelegate(KeyboardVisibilityListener listener)
|
||||
{
|
||||
m_keyboardVisibilityListener = listener;
|
||||
}
|
||||
|
||||
void initInputMethodManager(Activity activity)
|
||||
{
|
||||
this.m_keyboardVisibilityListener = listener;
|
||||
m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
}
|
||||
|
||||
@ -84,10 +88,10 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
final int candidatesStart, final int candidatesEnd)
|
||||
{
|
||||
QtNative.runAction(() -> {
|
||||
if (m_imm == null)
|
||||
return;
|
||||
|
||||
m_imm.updateSelection(m_currentEditText, selStart, selEnd, candidatesStart, candidatesEnd);
|
||||
if (m_imm != null) {
|
||||
m_imm.updateSelection(m_currentEditText, selStart, selEnd,
|
||||
candidatesStart, candidatesEnd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -104,12 +108,11 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
return;
|
||||
|
||||
m_currentEditText.setEditTextOptions(enterKeyType, inputHints);
|
||||
|
||||
m_currentEditText.setLayoutParams(new QtLayout.LayoutParams(width, height, x, y));
|
||||
|
||||
m_currentEditText.requestFocus();
|
||||
|
||||
m_currentEditText.postDelayed(() -> {
|
||||
if (m_imm == null)
|
||||
return;
|
||||
m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler()) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
@ -269,7 +272,8 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, Qt
|
||||
if (!visibility) {
|
||||
// Hiding the keyboard clears the immersive mode, so we need to set it again.
|
||||
m_keyboardVisibilityListener.onKeyboardVisibilityChange();
|
||||
m_currentEditText.clearFocus();
|
||||
if (m_currentEditText != null)
|
||||
m_currentEditText.clearFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user