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 Intent intent = getIntent();
171 if (intent == null)
172 return false;
173
174 final ComponentName component = intent.getComponent();
175 if (component == null)
176 return false;
177
178 final String launchedClassName = component.getClassName();
179 final String runtimeClassName = this.getClass().getName();
180
181 return !launchedClassName.equals(runtimeClassName);
182 }
183
184 @Override
185 protected void onPause()
186 {
187 super.onPause();
188 if (Build.VERSION.SDK_INT < 24 || !isInMultiWindowMode())
189 QtNative.setApplicationState(QtNative.ApplicationState.ApplicationInactive);
190 m_delegate.displayManager().unregisterDisplayListener();
191 m_delegate.getInputDelegate().unregisterBackGestureCallback(this);
192 }
193
194 @Override
195 protected void onResume()
196 {
197 super.onResume();
198 QtNative.setApplicationState(QtNative.ApplicationState.ApplicationActive);
199 if (QtNative.getStateDetails().isStarted) {
200 m_delegate.displayManager().registerDisplayListener();
201 QtWindow.updateWindows();
202 // Suspending the app clears the immersive mode, so we need to set it again.
203 QtWindowInsetsController.restoreFullScreenVisibility(this);
204 }
205 m_delegate.getInputDelegate().registerBackGestureCallback(this);
206 }
207
208 @Override
209 protected void onStop()
210 {
211 super.onStop();
212 QtNative.setApplicationState(QtNative.ApplicationState.ApplicationSuspended);
213 }
214
215 @Override
216 protected void onDestroy()
217 {
218 super.onDestroy();
219
220 if (!m_onCreateSucceeded)
221 System.exit(-1);
222
223 if (!m_retainNonConfigurationInstance) {
224 QtNative.unregisterAppStateListener(m_delegate);
225 QtNative.terminateQtNativeApplication();
226 QtNative.setActivity(null);
227 System.exit(0);
228 }
229 }
230
231 @Override
232 public void onConfigurationChanged(Configuration newConfig)
233 {
234 super.onConfigurationChanged(newConfig);
235
236 int diff = newConfig.diff(m_prevConfig);
237 if ((diff & ActivityInfo.CONFIG_UI_MODE) != 0)
238 m_delegate.handleUiModeChange();
239
240 if ((diff & ActivityInfo.CONFIG_LOCALE) != 0)
241 QtNative.updateLocale();
242
243 m_prevConfig = new Configuration(newConfig);
244 }
245
246 @Override
247 public boolean onContextItemSelected(MenuItem item)
248 {
249 m_delegate.setContextMenuVisible(false);
250 return QtNative.onContextItemSelected(item.getItemId(), item.isChecked());
251 }
252
253 @Override
254 public void onContextMenuClosed(Menu menu)
255 {
256 if (!m_delegate.isContextMenuVisible())
257 return;
258 m_delegate.setContextMenuVisible(false);
259 QtNative.onContextMenuClosed(menu);
260 }
261
262 @Override
263 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)
264 {
265 menu.clearHeader();
266 QtNative.onCreateContextMenu(menu);
267 m_delegate.setContextMenuVisible(true);
268 }
269
270 @Override
272 {
273 boolean handleResult = m_delegate.getInputDelegate().handleDispatchKeyEvent(event);
274 if (QtNative.getStateDetails().isStarted && handleResult)
275 return true;
276
277 return super.dispatchKeyEvent(event);
278 }
279
280 @Override
281 public boolean dispatchGenericMotionEvent(MotionEvent event)
282 {
283 boolean handled = m_delegate.getInputDelegate().handleDispatchGenericMotionEvent(event);
284 if (QtNative.getStateDetails().isStarted && handled)
285 return true;
286
287 return super.dispatchGenericMotionEvent(event);
288 }
289
290 @Override
291 public boolean onKeyDown(int keyCode, KeyEvent event)
292 {
293 QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails();
294 if (!stateDetails.isStarted || !stateDetails.nativePluginIntegrationReady)
295 return false;
296
297 return m_delegate.getInputDelegate().onKeyDown(keyCode, event);
298 }
299
300 @Override
301 public boolean onKeyUp(int keyCode, KeyEvent event)
302 {
303 QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails();
304 if (!stateDetails.isStarted || !stateDetails.nativePluginIntegrationReady)
305 return false;
306
307 return m_delegate.getInputDelegate().onKeyUp(keyCode, event);
308 }
309
310 @Override
311 public boolean onCreateOptionsMenu(Menu menu)
312 {
313 menu.clear();
314 return true;
315 }
316
317 @Override
318 public boolean onPrepareOptionsMenu(Menu menu)
319 {
320 boolean res = QtNative.onPrepareOptionsMenu(menu);
321 m_delegate.setActionBarVisibility(res && menu.size() > 0);
322 return res;
323 }
324
325 @Override
326 public boolean onOptionsItemSelected(MenuItem item)
327 {
328 return QtNative.onOptionsItemSelected(item.getItemId(), item.isChecked());
329 }
330
331 @Override
332 public void onOptionsMenuClosed(Menu menu)
333 {
334 QtNative.onOptionsMenuClosed(menu);
335 }
336
337 @Override
338 protected void onRestoreInstanceState(Bundle savedInstanceState)
339 {
340 super.onRestoreInstanceState(savedInstanceState);
341
342 // only restore when this Activity is being recreated for a config change
343 if (getLastNonConfigurationInstance() == null)
344 return;
345
346 QtNative.setStarted(savedInstanceState.getBoolean("Started"));
347 QtWindowInsetsController.restoreFullScreenVisibility(this);
348 // FIXME restore all surfaces
349 }
350
351 @Override
353 {
354 super.onRetainNonConfigurationInstance();
355 m_retainNonConfigurationInstance = true;
356 return true;
357 }
358
359 @Override
360 protected void onSaveInstanceState(Bundle outState)
361 {
362 super.onSaveInstanceState(outState);
363 outState.putBoolean("Started", QtNative.getStateDetails().isStarted);
364 }
365
366 @Override
367 public void onWindowFocusChanged(boolean hasFocus)
368 {
369 super.onWindowFocusChanged(hasFocus);
370 if (hasFocus)
371 QtWindowInsetsController.restoreFullScreenVisibility(this);
372 }
373
374 @Override
375 protected void onNewIntent(Intent intent)
376 {
377 addReferrer(intent);
378 QtNative.onNewIntent(intent);
379 }
380
381 @Override
382 protected void onActivityResult(int requestCode, int resultCode, Intent data)
383 {
384 super.onActivityResult(requestCode, resultCode, data);
385 QtNative.onActivityResult(requestCode, resultCode, data);
386 }
387
388 @Override
389 public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults)
390 {
391 QtNative.sendRequestPermissionsResult(requestCode, grantResults);
392 }
393
395 public void hideSplashScreen(final int duration)
396 {
397 m_delegate.hideSplashScreen(duration);
398 }
399}
[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)
GLvoid ** params
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
[0]
GLsizei const GLfloat * v
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]