Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
QtActivityBase.java
Go to the documentation of this file.
1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4package org.qtproject.qt.android;
5
6import android.annotation.SuppressLint;
7import android.app.Activity;
8import android.content.ComponentName;
9import android.content.Intent;
10import android.content.pm.ActivityInfo;
11import android.content.res.Configuration;
12import android.content.res.Resources;
13import android.net.Uri;
14import android.os.Build;
15import android.os.Bundle;
16import android.provider.Browser;
17import android.view.ContextMenu;
18import android.view.ContextMenu.ContextMenuInfo;
19import android.view.KeyEvent;
20import android.view.Menu;
21import android.view.MenuItem;
22import android.view.MotionEvent;
23import android.view.View;
24import android.view.Window;
25import android.util.Log;
26import java.lang.IllegalArgumentException;
27
28import android.widget.Toast;
29
30public class QtActivityBase extends Activity
31{
32 public static final String TAG = "QtActivityBase";
33 public static final String EXTRA_SOURCE_INFO = "org.qtproject.qt.android.sourceInfo";
34 public static final String EXTRA_FATAL_MESSAGE = "org.qtproject.qt.android.fatalMessage";
35
36 private String m_applicationParams = "";
37 private boolean m_isCustomThemeSet = false;
38 private boolean m_retainNonConfigurationInstance = false;
39 private Configuration m_prevConfig;
40 private final QtActivityDelegate m_delegate;
41 private boolean m_onCreateSucceeded = false;
42
43 private void addReferrer(Intent intent)
44 {
45 Bundle extras = intent.getExtras();
46 if (extras != null && extras.getString(EXTRA_SOURCE_INFO) != null)
47 return;
48
49 if (extras == null) {
50 Uri referrer = getReferrer();
51 if (referrer != null) {
52 String cleanReferrer = referrer.toString().replaceFirst("android-app://", "");
53 intent.putExtra(EXTRA_SOURCE_INFO, cleanReferrer);
54 }
55 } else {
56 String applicationId = extras.getString(Browser.EXTRA_APPLICATION_ID);
57 if (applicationId != null)
58 intent.putExtra(EXTRA_SOURCE_INFO, applicationId);
59 }
60 }
61
69 @SuppressWarnings("unused")
71 {
72 if (params == null || params.isEmpty())
73 return;
74
75 if (!m_applicationParams.isEmpty())
76 m_applicationParams += " ";
77 m_applicationParams += params;
78 }
79
80 @Override
81 public void setTheme(int resId) {
82 super.setTheme(resId);
83 m_isCustomThemeSet = true;
84 }
85
86 private void restartApplication() {
87 Intent intent = Intent.makeRestartActivityTask(getComponentName());
88 startActivity(intent);
89 QtNative.setStarted(false);
90 // FIXME: calling exit() right after this gives no time to get onDestroy().
91 finish();
92 Runtime.getRuntime().exit(0);
93 }
94
96 {
97 m_delegate = new QtActivityDelegate(this);
98 }
99
100 @Override
101 protected void onCreate(Bundle savedInstanceState)
102 {
103 super.onCreate(savedInstanceState);
104 requestWindowFeature(Window.FEATURE_ACTION_BAR);
105
106 if (!m_isCustomThemeSet) {
107 @SuppressWarnings("deprecation")
108 int themeId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
109 ? android.R.style.Theme_DeviceDefault_DayNight
110 : android.R.style.Theme_Holo_Light;
111 setTheme(themeId);
112 }
113
114 if (QtNative.getStateDetails().isStarted) {
115 // We don't yet have a reliable way to keep the app
116 // running properly in case of an Activity only restart,
117 // so for now restart the whole app.
118 restartApplication();
119 }
120
121 QtNative.registerAppStateListener(m_delegate);
122 addReferrer(getIntent());
123
124 try {
125 if (isLaunchedAsAlias()) {
126 Log.d(TAG, "Starting an alias-activity, skipping loading of the Qt libraries.");
127 } else {
128 QtActivityLoader loader = QtActivityLoader.getActivityLoader(this);
129 QtLoader.LoadingResult result = loader.loadQtLibraries();
130
131 if (result == QtLoader.LoadingResult.Failed) {
132 showFatalFinishingToast();
133 return;
134 }
135
136 if (result == QtLoader.LoadingResult.Succeeded) {
137 loader.appendApplicationParameters(m_applicationParams);
138 final String params = loader.getApplicationParameters();
139 m_delegate.startNativeApplication(params, loader.getMainLibraryPath());
140 }
141 }
142 } catch (IllegalArgumentException e) {
143 e.printStackTrace();
144 showFatalFinishingToast();
145 return;
146 }
147
148 m_prevConfig = new Configuration(getResources().getConfiguration());
149 m_onCreateSucceeded = true;
150 }
151
152 private void showFatalFinishingToast() {
153 Resources resources = getResources();
154 String packageName = getPackageName();
155 String message = null;
156 try {
157 @SuppressLint("DiscouragedApi")
158 int id = resources.getIdentifier("fatal_error_msg", "string", packageName);
159 message = resources.getString(id);
160 Toast.makeText(this, message, Toast.LENGTH_LONG).show();
161 } catch (Resources.NotFoundException ignored) { }
162 Intent fatalIntent = new Intent();
163 if (message != null)
164 fatalIntent.putExtra(EXTRA_FATAL_MESSAGE, message);
165 setResult(Activity.RESULT_CANCELED, fatalIntent);
166 super.finish();
167 }
168
169 private boolean isLaunchedAsAlias() {
170 final ComponentName component = getIntent().getComponent();
171 if (component == null)
172 return false;
173
174 final String launchedClassName = component.getClassName();
175 final String runtimeClassName = this.getClass().getName();
176
177 return !launchedClassName.equals(runtimeClassName);
178 }
179
180 @Override
181 protected void onPause()
182 {
183 super.onPause();
184 if (Build.VERSION.SDK_INT < 24 || !isInMultiWindowMode())
185 QtNative.setApplicationState(QtNative.ApplicationState.ApplicationInactive);
186 m_delegate.displayManager().unregisterDisplayListener();
187 m_delegate.getInputDelegate().unregisterBackGestureCallback(this);
188 }
189
190 @Override
191 protected void onResume()
192 {
193 super.onResume();
194 QtNative.setApplicationState(QtNative.ApplicationState.ApplicationActive);
195 if (QtNative.getStateDetails().isStarted) {
196 m_delegate.displayManager().registerDisplayListener();
197 QtWindow.updateWindows();
198 // Suspending the app clears the immersive mode, so we need to set it again.
199 QtWindowInsetsController.restoreFullScreenVisibility(this);
200 }
201 m_delegate.getInputDelegate().registerBackGestureCallback(this);
202 }
203
204 @Override
205 protected void onStop()
206 {
207 super.onStop();
208 QtNative.setApplicationState(QtNative.ApplicationState.ApplicationSuspended);
209 }
210
211 @Override
212 protected void onDestroy()
213 {
214 super.onDestroy();
215
216 if (!m_onCreateSucceeded)
217 System.exit(-1);
218
219 if (!m_retainNonConfigurationInstance) {
220 QtNative.unregisterAppStateListener(m_delegate);
221 QtNative.terminateQtNativeApplication();
222 QtNative.setActivity(null);
223 System.exit(0);
224 }
225 }
226
227 @Override
228 public void onConfigurationChanged(Configuration newConfig)
229 {
230 super.onConfigurationChanged(newConfig);
231
232 int diff = newConfig.diff(m_prevConfig);
233 if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0)
234 m_delegate.handleUiModeChange();
235
236 if ((diff & ActivityInfo.CONFIG_LOCALE) != 0)
237 QtNative.updateLocale();
238
239 m_prevConfig = new Configuration(newConfig);
240 }
241
242 @Override
243 public boolean onContextItemSelected(MenuItem item)
244 {
245 m_delegate.setContextMenuVisible(false);
246 return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
247 }
248
249 @Override
250 public void onContextMenuClosed(Menu menu)
251 {
252 if (!m_delegate.isContextMenuVisible())
253 return;
254 m_delegate.setContextMenuVisible(false);
255 QtNative.onContextMenuClosed(menu);
256 }
257
258 @Override
259 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
260 {
261 menu.clearHeader();
262 QtNative.onCreateContextMenu(menu);
263 m_delegate.setContextMenuVisible(true);
264 }
265
266 @Override
268 {
269 boolean handleResult = m_delegate.getInputDelegate().handleDispatchKeyEvent(event);
270 if (QtNative.getStateDetails().isStarted && handleResult)
271 return true;
272
273 return super.dispatchKeyEvent(event);
274 }
275
276 @Override
277 public boolean dispatchGenericMotionEvent(MotionEvent event)
278 {
279 boolean handled = m_delegate.getInputDelegate().handleDispatchGenericMotionEvent(event);
280 if (QtNative.getStateDetails().isStarted && handled)
281 return true;
282
283 return super.dispatchGenericMotionEvent(event);
284 }
285
286 @Override
287 public boolean onKeyDown(int keyCode, KeyEvent event)
288 {
289 QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails();
290 if (!stateDetails.isStarted || !stateDetails.nativePluginIntegrationReady)
291 return false;
292
293 return m_delegate.getInputDelegate().onKeyDown(keyCode, event);
294 }
295
296 @Override
297 public boolean onKeyUp(int keyCode, KeyEvent event)
298 {
299 QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails();
300 if (!stateDetails.isStarted || !stateDetails.nativePluginIntegrationReady)
301 return false;
302
303 return m_delegate.getInputDelegate().onKeyUp(keyCode, event);
304 }
305
306 @Override
307 public boolean onCreateOptionsMenu(Menu menu)
308 {
309 menu.clear();
310 return true;
311 }
312
313 @Override
314 public boolean onPrepareOptionsMenu(Menu menu)
315 {
316 boolean res = QtNative.onPrepareOptionsMenu(menu);
317 m_delegate.setActionBarVisibility(res && menu.size() > 0);
318 return res;
319 }
320
321 @Override
322 public boolean onOptionsItemSelected(MenuItem item)
323 {
324 return QtNative.onOptionsItemSelected(item.getItemId(), item.isChecked());
325 }
326
327 @Override
328 public void onOptionsMenuClosed(Menu menu)
329 {
330 QtNative.onOptionsMenuClosed(menu);
331 }
332
333 @Override
334 protected void onRestoreInstanceState(Bundle savedInstanceState)
335 {
336 super.onRestoreInstanceState(savedInstanceState);
337
338 // only restore when this Activity is being recreated for a config change
339 if (getLastNonConfigurationInstance() == null)
340 return;
341
342 QtNative.setStarted(savedInstanceState.getBoolean("Started"));
343 QtWindowInsetsController.restoreFullScreenVisibility(this);
344 // FIXME restore all surfaces
345 }
346
347 @Override
349 {
350 super.onRetainNonConfigurationInstance();
351 m_retainNonConfigurationInstance = true;
352 return true;
353 }
354
355 @Override
356 protected void onSaveInstanceState(Bundle outState)
357 {
358 super.onSaveInstanceState(outState);
359 outState.putBoolean("Started", QtNative.getStateDetails().isStarted);
360 }
361
362 @Override
363 public void onWindowFocusChanged(boolean hasFocus)
364 {
365 super.onWindowFocusChanged(hasFocus);
366 if (hasFocus)
367 QtWindowInsetsController.restoreFullScreenVisibility(this);
368 }
369
370 @Override
371 protected void onNewIntent(Intent intent)
372 {
373 addReferrer(intent);
374 QtNative.onNewIntent(intent);
375 }
376
377 @Override
378 protected void onActivityResult(int requestCode, int resultCode, Intent data)
379 {
380 super.onActivityResult(requestCode, resultCode, data);
381 QtNative.onActivityResult(requestCode, resultCode, data);
382 }
383
384 @Override
385 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
386 {
387 QtNative.sendRequestPermissionsResult(requestCode, grantResults);
388 }
389
391 public void hideSplashScreen(final int duration)
392 {
393 m_delegate.hideSplashScreen(duration);
394 }
395}
[Window class with invokable method]
Definition window.h:11
void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
boolean dispatchGenericMotionEvent(MotionEvent event)
boolean onKeyDown(int keyCode, KeyEvent event)
void onCreate(Bundle savedInstanceState)
void onActivityResult(int requestCode, int resultCode, Intent data)
void onConfigurationChanged(Configuration newConfig)
boolean onKeyUp(int keyCode, KeyEvent event)
void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
void onRestoreInstanceState(Bundle savedInstanceState)
static native void onNewIntent(Intent data)
#define this
Definition dialogs.cpp:8
QMap< Name, StatePointer > Bundle
Definition lalr.h:46
[vector_of_multirole_objects_0]
Definition main.cpp:188
static QStringList getResources(const QString &resourceFile, QMakeVfs *vfs)
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
[0]
GLuint GLsizei const GLchar * message
GLsizei const GLfloat * v
void ** params
struct _cl_event * event
GLuint res
GLuint64EXT * result
[6]
static qreal component(const QPointF &point, unsigned int i)
static QString getString(IMFActivate *device, const IID &id)
view show()
[18] //! [19]
void handleResult(const QFuture< T > &future)
QMenu menu
[5]
if(foo.startsWith("("+type+") 0x")) ... QString hello("hello")
[0]