Android: Let QtLoader handle different Contexts when initializing

QtLoader now calls the correct methods when initializing static classes
and retrieving ContextInfo based on the type of the Context (Activity
or Service). This is done to avoid the need for code duplication when
introducing other QtLoader sub classes that deal with the same Context
types, such as the loader for the use case where Qt is used from a
native Android app.
Abstract methods and their implementations in subclasses
aimed at handling this removed as a result.

Pick-to: 6.7
Change-Id: I6cda8e4733594a6a3963cf0fd8217de2fbd408f8
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
bb10
Tinja Paavoseppä 2024-01-11 09:57:20 +02:00
parent e066172c49
commit 24a0d958a7
3 changed files with 60 additions and 67 deletions

View File

@ -8,6 +8,7 @@ import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@ -26,23 +27,12 @@ class QtActivityLoader extends QtLoader {
public QtActivityLoader(Activity activity)
{
super(activity);
super(new ContextWrapper(activity));
m_activity = activity;
extractContextMetaData();
}
@Override
protected void initContextInfo() {
try {
m_contextInfo = m_context.getPackageManager().getActivityInfo(
((Activity)m_context).getComponentName(), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
finish();
}
}
private void showErrorDialog() {
if (m_activity == null) {
Log.w(QtTAG, "cannot show the error dialog from a null activity object");
@ -69,16 +59,6 @@ class QtActivityLoader extends QtLoader {
m_activity.finish();
}
@Override
protected void initStaticClassesImpl(Class<?> initClass, Object staticInitDataObject) {
try {
Method m = initClass.getMethod("setActivity", Activity.class, Object.class);
m.invoke(staticInitDataObject, m_activity, this);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
Log.d(QtTAG, "Class " + initClass.getName() + " does not implement setActivity method");
}
}
private String getDecodedUtfString(String str)
{
byte[] decodedExtraEnvVars = Base64.decode(str, Base64.DEFAULT);

View File

@ -5,9 +5,13 @@
package org.qtproject.qt.android;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ComponentInfo;
import android.content.res.Resources;
import android.os.Build;
@ -58,13 +62,6 @@ abstract class QtLoader {
initContextInfo();
}
/**
* Initializes the context info instance which is used to retrieve
* the app metadata from the AndroidManifest.xml or other xml resources.
* Some values are dependent on the context being an Activity or Service.
**/
abstract protected void initContextInfo();
/**
* Implements the logic for finish the extended context, mostly called
* in error cases.
@ -72,10 +69,29 @@ abstract class QtLoader {
abstract protected void finish();
/**
* Context specific (Activity/Service) implementation for static classes.
* The Activity and Service loaders call different methods.
* Initializes the context info instance which is used to retrieve
* the app metadata from the AndroidManifest.xml or other xml resources.
* Some values are dependent on the context being an Activity or Service.
**/
abstract protected void initStaticClassesImpl(Class<?> initClass, Object staticInitDataObject);
protected void initContextInfo() {
try {
Context context = m_context.getBaseContext();
if (context instanceof Activity) {
m_contextInfo = context.getPackageManager().getActivityInfo(
((Activity)context).getComponentName(), PackageManager.GET_META_DATA);
} else if (context instanceof Service) {
m_contextInfo = context.getPackageManager().getServiceInfo(
new ComponentName(context, context.getClass()),
PackageManager.GET_META_DATA);
} else {
Log.w(QtTAG, "Context is not an instance of Activity or Service, could not get " +
"context info for it");
}
} catch (Exception e) {
e.printStackTrace();
finish();
}
}
/**
* Extract the common metadata in the base implementation. And the extended methods
@ -123,18 +139,41 @@ abstract class QtLoader {
}
private void initStaticClasses() {
Context context = m_context.getBaseContext();
boolean isActivity = context instanceof Activity;
for (String className : getStaticInitClasses()) {
try {
Class<?> initClass = m_classLoader.loadClass(className);
Object staticInitDataObject = initClass.newInstance(); // create an instance
initStaticClassesImpl(initClass, staticInitDataObject);
// For modules that don't need/have setActivity/setService
Method m = initClass.getMethod("setContext", Context.class);
m.invoke(staticInitDataObject, m_context);
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException |
NoSuchMethodException | InvocationTargetException e) {
Log.d(QtTAG, "Class " + className + " does not implement setContext method");
if (isActivity) {
try {
Method m = initClass.getMethod("setActivity", Activity.class, Object.class);
m.invoke(staticInitDataObject, (Activity) context, this);
} catch (InvocationTargetException | NoSuchMethodException e) {
Log.d(QtTAG, "Class " + initClass.getName() + " does not implement " +
"setActivity method");
}
} else {
try {
Method m = initClass.getMethod("setService", Service.class, Object.class);
m.invoke(staticInitDataObject, (Service) context, this);
} catch (InvocationTargetException | NoSuchMethodException e) {
Log.d(QtTAG, "Class " + initClass.getName() + " does not implement " +
"setService method");
}
}
try {
// For modules that don't need/have setActivity/setService
Method m = initClass.getMethod("setContext", Context.class);
m.invoke(staticInitDataObject, context);
} catch (InvocationTargetException | NoSuchMethodException e) {
Log.d(QtTAG, "Class " + initClass.getName() + " does not implement " +
"setContext method");
}
} catch (IllegalAccessException | ClassNotFoundException | InstantiationException e) {
Log.d(QtTAG, "Could not instantiate class " + className + ", " + e);
}
}
}

View File

@ -5,35 +5,19 @@
package org.qtproject.qt.android;
import android.app.Service;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.ContextWrapper;
import android.util.Log;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class QtServiceLoader extends QtLoader {
private final Service m_service;
public QtServiceLoader(Service service) {
super(service);
super(new ContextWrapper(service));
m_service = service;
extractContextMetaData();
}
@Override
protected void initContextInfo() {
try {
m_contextInfo = m_context.getPackageManager().getServiceInfo(
new ComponentName(m_context, m_context.getClass()),
PackageManager.GET_META_DATA);
} catch (Exception e) {
e.printStackTrace();
finish();
}
}
@Override
protected void finish() {
if (m_service != null)
@ -41,14 +25,4 @@ class QtServiceLoader extends QtLoader {
else
Log.w(QtTAG, "finish() called when service object is null");
}
@Override
protected void initStaticClassesImpl(Class<?> initClass, Object staticInitDataObject) {
try {
Method m = initClass.getMethod("setService", Service.class, Object.class);
m.invoke(staticInitDataObject, m_service, this);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
Log.d(QtTAG, "Class " + initClass.getName() + " does not implement setService method");
}
}
}