39 private static WeakReference<Activity> m_activity =
null;
40 private static WeakReference<Service> m_service =
null;
41 private static final Object m_mainActivityMutex =
new Object();
43 private static final ApplicationStateDetails m_stateDetails =
new ApplicationStateDetails();
45 static final String QtTAG =
"Qt JAVA";
48 private static final BackgroundActionsTracker m_backgroundActionsTracker =
new BackgroundActionsTracker();
49 private static QtThread m_qtThread =
null;
50 private static final Object m_qtThreadLock =
new Object();
51 private static ClassLoader m_classLoader =
null;
53 private static final Runnable runPendingCppRunnablesRunnable = QtNative::runPendingCppRunnables;
54 private static final ArrayList<AppStateDetailsListener> m_appStateListeners =
new ArrayList<>();
55 private static final Object m_appStateListenersLock =
new Object();
58 static ClassLoader classLoader()
63 static void setClassLoader(ClassLoader classLoader)
65 m_classLoader = classLoader;
68 static void setActivity(Activity qtMainActivity)
70 synchronized (m_mainActivityMutex) {
71 m_activity =
new WeakReference<>(qtMainActivity);
73 if (m_stateDetails.isStarted)
74 updateNativeActivity();
75 }
catch (UnsatisfiedLinkError ignored) {
83 static void setService(Service qtMainService)
85 synchronized (m_mainActivityMutex) {
86 m_service =
new WeakReference<>(qtMainService);
91 static Activity activity()
93 synchronized (m_mainActivityMutex) {
94 return m_activity !=
null ? m_activity.get() :
null;
98 static boolean isActivityValid()
100 return m_activity !=
null && m_activity.get() !=
null;
104 static Service service()
106 synchronized (m_mainActivityMutex) {
107 return m_service !=
null ? m_service.get() :
null;
111 static boolean isServiceValid()
113 return m_service !=
null && m_service.get() !=
null;
118 if (isActivityValid())
119 return m_activity.get();
126 return joinedString.split(
",");
129 private static String getCurrentMethodNameLog()
131 return new Exception().getStackTrace()[1].getMethodName() +
": ";
139 parsedUri = Uri.parse(uri);
140 }
catch (NullPointerException e) {
146 String scheme = parsedUri.getScheme();
149 if (scheme !=
null && scheme.compareTo(
"content") != 0)
153 String uriStr = parsedUri.getPath();
155 for (
int i = 0; i < permissions.size(); ++i) {
156 Uri iterUri = permissions.get(i).getUri();
157 boolean isRequestPermission = permissions.get(i).isReadPermission();
159 if (!openMode.equals(
"r"))
160 isRequestPermission = permissions.get(i).isWritePermission();
162 final boolean isSameAuthority =
163 Objects.equals(iterUri.getAuthority(), parsedUri.getAuthority());
164 final boolean isSamePath = Objects.equals(iterUri.getPath(), uriStr);
166 if (isSameAuthority && isSamePath && isRequestPermission) {
175 }
catch (SecurityException e) {
176 Log.e(QtTAG, getCurrentMethodNameLog() + e);
184 final Uri uri = getUriWithValidPermission(
context,
url,
"r");
186 Log.e(QtTAG, getCurrentMethodNameLog() +
"received invalid/null Uri");
191 Intent intent =
new Intent(Intent.ACTION_VIEW, uri);
192 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
194 intent.setDataAndType(uri, mime);
196 Activity activity = activity();
197 if (activity ==
null) {
198 Log.w(QtTAG,
"openURL(): The activity reference is null");
202 activity.startActivity(intent);
205 }
catch (Exception e) {
206 Log.e(QtTAG, getCurrentMethodNameLog() + e);
211 static QtThread getQtThread() {
212 if (m_qtThread !=
null && m_qtThread.isAlive())
215 synchronized (m_qtThreadLock) {
216 if (m_qtThread ==
null || !m_qtThread.isAlive())
217 m_qtThread =
new QtThread();
229 static class ApplicationState {
230 static final int ApplicationSuspended = 0x0;
231 static final int ApplicationHidden = 0x1;
232 static final int ApplicationInactive = 0x2;
233 static final int ApplicationActive = 0x4;
236 static class ApplicationStateDetails {
237 int state = ApplicationState.ApplicationSuspended;
238 boolean nativePluginIntegrationReady =
false;
239 boolean isStarted =
false;
242 static ApplicationStateDetails getStateDetails()
244 return m_stateDetails;
247 static void setStarted(
boolean started)
249 m_stateDetails.isStarted = started;
250 notifyAppStateDetailsChanged(m_stateDetails);
254 static void notifyNativePluginIntegrationReady(
boolean ready)
256 m_stateDetails.nativePluginIntegrationReady = ready;
257 notifyNativePluginIntegrationReadyChanged(ready);
258 notifyAppStateDetailsChanged(m_stateDetails);
261 final String bufferSize = Os.getenv(
"QT_ANDROID_BACKGROUND_ACTIONS_QUEUE_SIZE");
262 if (bufferSize !=
null) {
265 m_backgroundActionsTracker.setMaxAllowedActions(
size);
266 }
catch (NumberFormatException exception) {
267 Log.e(QtTAG,
"Parsing failed, QT_ANDROID_BACKGROUND_ACTIONS_QUEUE_SIZE value is not an integer");
272 static void setApplicationState(
int state)
274 synchronized (m_mainActivityMutex) {
275 m_stateDetails.state =
state;
276 if (
state == ApplicationState.ApplicationActive)
277 m_backgroundActionsTracker.processActions();
279 updateApplicationState(
state);
280 notifyAppStateDetailsChanged(m_stateDetails);
284 synchronized (m_appStateListenersLock) {
285 if (!m_appStateListeners.contains(listener))
286 m_appStateListeners.add(listener);
291 synchronized (m_appStateListenersLock) {
292 m_appStateListeners.remove(listener);
296 static void notifyNativePluginIntegrationReadyChanged(
boolean ready) {
297 synchronized (m_appStateListenersLock) {
299 listener.onNativePluginIntegrationReadyChanged(ready);
303 static void notifyAppStateDetailsChanged(ApplicationStateDetails details) {
304 synchronized (m_appStateListenersLock) {
306 listener.onAppStateDetailsChanged(details);
312 static void runAction(Runnable action)
314 runAction(action,
true);
317 static void runAction(Runnable action,
boolean queueWhenInactive)
319 synchronized (m_mainActivityMutex) {
320 final Looper mainLooper = Looper.getMainLooper();
323 if (queueWhenInactive) {
324 final boolean isStateVisible =
325 (m_stateDetails.state != ApplicationState.ApplicationSuspended)
326 && (m_stateDetails.state != ApplicationState.ApplicationHidden);
327 final boolean active = (isActivityValid() && isStateVisible) || isServiceValid();
328 if (!active || !
handler.post(action))
329 m_backgroundActionsTracker.enqueue(action);
337 private static void runPendingCppRunnablesOnAndroidThread()
339 synchronized (m_mainActivityMutex) {
340 if (isActivityValid()) {
341 if (m_stateDetails.state == ApplicationState.ApplicationActive)
342 m_activity.get().runOnUiThread(runPendingCppRunnablesRunnable);
344 runAction(runPendingCppRunnablesRunnable);
346 final Looper mainLooper = Looper.getMainLooper();
347 final Thread looperThread = mainLooper.getThread();
348 if (looperThread.equals(Thread.currentThread())) {
349 runPendingCppRunnablesRunnable.run();
352 handler.post(runPendingCppRunnablesRunnable);
359 private static void setViewVisibility(
final View
view,
final boolean visible)
361 runAction(() ->
view.setVisibility(visible ? View.VISIBLE : View.GONE));
366 if (m_stateDetails.isStarted)
369 getQtThread().run(() -> initAndroidQpaPlugin());
371 getQtThread().post(() -> { startQtNativeApplication(qtParams); });
372 waitForServiceSetup();
377 static int checkSelfPermission(
String permission)
379 synchronized (m_mainActivityMutex) {
381 PackageManager pm =
context.getPackageManager();
382 return pm.checkPermission(permission,
context.getPackageName());
387 private static byte[][] getSSLCertificates()
389 ArrayList<byte[]> certificateList =
new ArrayList<>();
392 TrustManagerFactory
factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
396 if (
manager instanceof X509TrustManager) {
397 X509TrustManager trustManager = (X509TrustManager)
manager;
399 for (X509Certificate certificate : trustManager.getAcceptedIssuers()) {
400 byte[]
buffer = certificate.getEncoded();
401 certificateList.add(
buffer);
405 }
catch (Exception e) {
406 Log.e(QtTAG,
"Failed to get certificates", e);
409 byte[][] certificateArray =
new byte[certificateList.size()][];
410 certificateArray = certificateList.toArray(certificateArray);
411 return certificateArray;
415 private static String[] listAssetContent(android.content.res.AssetManager asset,
String path) {
417 ArrayList<String>
res =
new ArrayList<>();
424 if (isDir !=
null && isDir.length > 0)
427 }
catch (Exception e) {
432 }
catch (Exception e) {
439 static native
boolean initAndroidQpaPlugin();
440 static native
void startQtNativeApplication(
String params);
441 static native
void waitForServiceSetup();
442 static native
void terminateQtNativeApplication();
443 static native
boolean updateNativeActivity();
447 static native
void updateApplicationState(
int state);
448 static native
void updateLocale();
451 static native
boolean onPrepareOptionsMenu(Menu
menu);
452 static native
boolean onOptionsItemSelected(
int itemId,
boolean checked);
453 static native
void onOptionsMenuClosed(Menu
menu);
455 static native
void onCreateContextMenu(ContextMenu
menu);
456 static native
void fillContextMenu(Menu
menu);
457 static native
boolean onContextItemSelected(
int itemId,
boolean checked);
458 static native
void onContextMenuClosed(Menu
menu);
462 static native
void onActivityResult(
int requestCode,
int resultCode, Intent
data);
465 static native
void runPendingCppRunnables();
467 static native
void sendRequestPermissionsResult(
int requestCode,
int[] grantResults);
471 static native IBinder onBind(Intent intent);