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