From a3201f2023bb51818d7106695ae61fded555d3ef Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Tue, 15 Mar 2016 16:00:33 -0700 Subject: [PATCH] Move SkyApplication initialization into SkyMain This allows Flutter embedders to set up Flutter from their own application class instead of using or subclassing SkyApplication --- .../org/domokit/sky/shell/SkyActivity.java | 2 +- .../org/domokit/sky/shell/SkyApplication.java | 217 +----------------- .../org/domokit/sky/shell/SkyMain.java | 204 +++++++++++++++- 3 files changed, 206 insertions(+), 217 deletions(-) diff --git a/sky/shell/platform/android/org/domokit/sky/shell/SkyActivity.java b/sky/shell/platform/android/org/domokit/sky/shell/SkyActivity.java index dd4ef62cd0b..40bc1f32549 100644 --- a/sky/shell/platform/android/org/domokit/sky/shell/SkyActivity.java +++ b/sky/shell/platform/android/org/domokit/sky/shell/SkyActivity.java @@ -132,7 +132,7 @@ public class SkyActivity extends Activity { return; } File dataDir = new File(PathUtils.getDataDirectory(this)); - File appBundle = new File(dataDir, SkyApplication.APP_BUNDLE); + File appBundle = new File(dataDir, SkyMain.APP_BUNDLE); if (appBundle.exists()) { mView.runFromBundle(appBundle.getPath(), null); return; diff --git a/sky/shell/platform/android/org/domokit/sky/shell/SkyApplication.java b/sky/shell/platform/android/org/domokit/sky/shell/SkyApplication.java index cfefecdf199..12b4b652957 100644 --- a/sky/shell/platform/android/org/domokit/sky/shell/SkyApplication.java +++ b/sky/shell/platform/android/org/domokit/sky/shell/SkyApplication.java @@ -4,225 +4,16 @@ package org.domokit.sky.shell; -import android.content.Context; -import android.content.res.AssetManager; -import android.util.Log; -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.InputStreamReader; -import java.io.IOException; -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.JSONTokener; - -import org.chromium.base.BaseChromiumApplication; -import org.chromium.base.library_loader.LibraryLoader; -import org.chromium.base.library_loader.LibraryProcessType; -import org.chromium.base.library_loader.ProcessInitException; -import org.chromium.base.PathUtils; -import org.chromium.mojo.sensors.SensorServiceImpl; -import org.chromium.mojo.system.Core; -import org.chromium.mojo.system.MessagePipeHandle; -import org.chromium.mojom.activity.Activity; -import org.chromium.mojom.activity.PathService; -import org.chromium.mojom.flutter.platform.HapticFeedback; -import org.chromium.mojom.flutter.platform.PathProvider; -import org.chromium.mojom.flutter.platform.SystemChrome; -import org.chromium.mojom.flutter.platform.SystemSound; -import org.chromium.mojom.media.MediaService; -import org.chromium.mojom.mojo.NetworkService; -import org.chromium.mojom.sensors.SensorService; -import org.chromium.mojom.vsync.VSyncProvider; -import org.domokit.activity.ActivityImpl; -import org.domokit.activity.PathServiceImpl; -import org.domokit.media.MediaServiceImpl; -import org.domokit.oknet.NetworkServiceImpl; -import org.domokit.platform.HapticFeedbackImpl; -import org.domokit.platform.PathProviderImpl; -import org.domokit.platform.SystemChromeImpl; -import org.domokit.platform.SystemSoundImpl; -import org.domokit.vsync.VSyncProviderImpl; +import android.app.Application; /** * Sky implementation of {@link android.app.Application}, managing application-level global - * state and initializations. + * initializations. */ -public class SkyApplication extends BaseChromiumApplication { - public static final String APP_BUNDLE = "app.flx"; - static final String MANIFEST = "flutter.yaml"; - static final String SERVICES = "services.json"; - - private static final String TAG = "SkyApplication"; - private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "sky_shell"; - private static final String[] SKY_RESOURCES = {"icudtl.dat", APP_BUNDLE, MANIFEST}; - - private ResourceExtractor mResourceExtractor; - - public ResourceExtractor getResourceExtractor() { - return mResourceExtractor; - } - +public class SkyApplication extends Application { @Override public void onCreate() { super.onCreate(); - initJavaUtils(); - initResources(); - initNative(); - onServiceRegistryAvailable(ServiceRegistry.SHARED); - } - - /** - * Override this function to add more resources for extraction. - */ - protected void onBeforeResourceExtraction(ResourceExtractor extractor) { - extractor.addResources(SKY_RESOURCES); - } - - /** - * Override this function to register more services. - */ - protected void onServiceRegistryAvailable(ServiceRegistry registry) { - parseServicesConfig(registry); - - registry.register(Activity.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - Activity.MANAGER.bind(new ActivityImpl(), pipe); - } - }); - - registry.register(PathService.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - PathService.MANAGER.bind(new PathServiceImpl(getApplicationContext()), pipe); - } - }); - - registry.register(MediaService.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - MediaService.MANAGER.bind(new MediaServiceImpl(context, core), pipe); - } - }); - - registry.register(NetworkService.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - NetworkService.MANAGER.bind(new NetworkServiceImpl(context, core), pipe); - } - }); - - registry.register(SensorService.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - SensorService.MANAGER.bind(new SensorServiceImpl(context), pipe); - } - }); - - registry.register(VSyncProvider.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - VSyncProvider.MANAGER.bind(new VSyncProviderImpl(pipe), pipe); - } - }); - - registry.register(HapticFeedback.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - HapticFeedback.MANAGER.bind(new HapticFeedbackImpl(), pipe); - } - }); - - registry.register(PathProvider.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - PathProvider.MANAGER.bind(new PathProviderImpl(context), pipe); - } - }); - - registry.register(SystemChrome.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - SystemChrome.MANAGER.bind(new SystemChromeImpl(), pipe); - } - }); - - registry.register(SystemSound.MANAGER.getName(), new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - SystemSound.MANAGER.bind(new SystemSoundImpl(), pipe); - } - }); - } - - /** - * Parses the auto-generated services.json file, which contains additional services to register. - */ - private void parseServicesConfig(ServiceRegistry registry) { - final AssetManager manager = getResources().getAssets(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(manager.open(SERVICES)))) { - StringBuffer json = new StringBuffer(); - while (true) { - String line = reader.readLine(); - if (line == null) - break; - json.append(line); - } - - JSONObject object = (JSONObject) new JSONTokener(json.toString()).nextValue(); - JSONArray services = object.getJSONArray("services"); - for (int i = 0; i < services.length(); ++i) { - JSONObject service = services.getJSONObject(i); - String serviceName = service.getString("name"); - String className = service.getString("class"); - registerService(registry, serviceName, className); - } - } catch (FileNotFoundException e) { - // Not all apps will have a services.json file. - return; - } catch (Exception e) { - Log.e(TAG, "Failure parsing service configuration file", e); - return; - } - } - - /** - * Registers a third-party service. - */ - private void registerService(ServiceRegistry registry, final String serviceName, final String className) { - registry.register(serviceName, new ServiceFactory() { - @Override - public void connectToService(Context context, Core core, MessagePipeHandle pipe) { - try { - Class.forName(className) - .getMethod("connectToService", Context.class, Core.class, MessagePipeHandle.class) - .invoke(null, context, core, pipe); - } catch(Exception e) { - Log.e(TAG, "Failed to register service '" + serviceName + "'", e); - } - } - }); - } - - private void initJavaUtils() { - PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX, - getApplicationContext()); - } - - private void initResources() { - Context context = getApplicationContext(); - new ResourceCleaner(context).start(); - mResourceExtractor = new ResourceExtractor(context); - onBeforeResourceExtraction(mResourceExtractor); - mResourceExtractor.start(); - } - - private void initNative() { - try { - LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(this); - } catch (ProcessInitException e) { - Log.e(TAG, "Unable to load Sky Engine binary.", e); - throw new RuntimeException(e); - } + SkyMain.startInit(this); } } diff --git a/sky/shell/platform/android/org/domokit/sky/shell/SkyMain.java b/sky/shell/platform/android/org/domokit/sky/shell/SkyMain.java index f17cbe4651a..3ad1d4e1148 100644 --- a/sky/shell/platform/android/org/domokit/sky/shell/SkyMain.java +++ b/sky/shell/platform/android/org/domokit/sky/shell/SkyMain.java @@ -6,9 +6,44 @@ package org.domokit.sky.shell; import android.content.Context; import android.util.Log; +import android.content.res.AssetManager; +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.InputStreamReader; +import java.io.IOException; +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONTokener; import org.chromium.base.JNINamespace; +import org.chromium.base.PathUtils; +import org.chromium.base.library_loader.LibraryLoader; +import org.chromium.base.library_loader.LibraryProcessType; +import org.chromium.base.library_loader.ProcessInitException; +import org.chromium.mojo.sensors.SensorServiceImpl; +import org.chromium.mojo.system.Core; import org.chromium.mojo.system.impl.CoreImpl; +import org.chromium.mojo.system.MessagePipeHandle; +import org.chromium.mojom.activity.Activity; +import org.chromium.mojom.activity.PathService; +import org.chromium.mojom.flutter.platform.HapticFeedback; +import org.chromium.mojom.flutter.platform.PathProvider; +import org.chromium.mojom.flutter.platform.SystemChrome; +import org.chromium.mojom.flutter.platform.SystemSound; +import org.chromium.mojom.media.MediaService; +import org.chromium.mojom.mojo.NetworkService; +import org.chromium.mojom.sensors.SensorService; +import org.chromium.mojom.vsync.VSyncProvider; +import org.domokit.activity.ActivityImpl; +import org.domokit.activity.PathServiceImpl; +import org.domokit.media.MediaServiceImpl; +import org.domokit.oknet.NetworkServiceImpl; +import org.domokit.platform.HapticFeedbackImpl; +import org.domokit.platform.PathProviderImpl; +import org.domokit.platform.SystemChromeImpl; +import org.domokit.platform.SystemSoundImpl; +import org.domokit.vsync.VSyncProviderImpl; + /** * A class to intialize the native code. @@ -17,21 +52,39 @@ import org.chromium.mojo.system.impl.CoreImpl; public class SkyMain { private static final String TAG = "SkyMain"; + public static final String APP_BUNDLE = "app.flx"; + private static final String MANIFEST = "flutter.yaml"; + private static final String SERVICES = "services.json"; + + private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "sky_shell"; + private static final String[] SKY_RESOURCES = {"icudtl.dat", APP_BUNDLE, MANIFEST}; + /** * A guard flag for calling nativeInit() only once. **/ private static boolean sInitialized = false; + private static ResourceExtractor sResourceExtractor; + /** - * Initializes the native system. + * Starts initialization of the native system. + **/ + public static void startInit(Context applicationContext) { + initJavaUtils(applicationContext); + initResources(applicationContext); + initNative(applicationContext); + onServiceRegistryAvailable(applicationContext, ServiceRegistry.SHARED); + } + + /** + * Blocks until initialization of the native system has completed. **/ public static void ensureInitialized(Context applicationContext, String[] args) { if (sInitialized) { return; } try { - SkyApplication app = (SkyApplication) applicationContext; - app.getResourceExtractor().waitForCompletion(); + sResourceExtractor.waitForCompletion(); nativeInit(applicationContext, args); // Create the mojo run loop. CoreImpl.getInstance().createDefaultRunLoop(); @@ -43,4 +96,149 @@ public class SkyMain { } private static native void nativeInit(Context context, String[] args); + + private static void onServiceRegistryAvailable(final Context applicationContext, ServiceRegistry registry) { + parseServicesConfig(applicationContext, registry); + + registry.register(Activity.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + Activity.MANAGER.bind(new ActivityImpl(), pipe); + } + }); + + registry.register(PathService.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + PathService.MANAGER.bind(new PathServiceImpl(applicationContext), pipe); + } + }); + + registry.register(MediaService.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + MediaService.MANAGER.bind(new MediaServiceImpl(context, core), pipe); + } + }); + + registry.register(NetworkService.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + NetworkService.MANAGER.bind(new NetworkServiceImpl(context, core), pipe); + } + }); + + registry.register(SensorService.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + SensorService.MANAGER.bind(new SensorServiceImpl(context), pipe); + } + }); + + registry.register(VSyncProvider.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + VSyncProvider.MANAGER.bind(new VSyncProviderImpl(pipe), pipe); + } + }); + + registry.register(HapticFeedback.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + HapticFeedback.MANAGER.bind(new HapticFeedbackImpl(), pipe); + } + }); + + registry.register(PathProvider.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + PathProvider.MANAGER.bind(new PathProviderImpl(context), pipe); + } + }); + + registry.register(SystemChrome.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + SystemChrome.MANAGER.bind(new SystemChromeImpl(), pipe); + } + }); + + registry.register(SystemSound.MANAGER.getName(), new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + SystemSound.MANAGER.bind(new SystemSoundImpl(), pipe); + } + }); + } + + /** + * Parses the auto-generated services.json file, which contains additional services to register. + */ + private static void parseServicesConfig(Context applicationContext, ServiceRegistry registry) { + final AssetManager manager = applicationContext.getResources().getAssets(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(manager.open(SERVICES)))) { + StringBuffer json = new StringBuffer(); + while (true) { + String line = reader.readLine(); + if (line == null) + break; + json.append(line); + } + + JSONObject object = (JSONObject) new JSONTokener(json.toString()).nextValue(); + JSONArray services = object.getJSONArray("services"); + for (int i = 0; i < services.length(); ++i) { + JSONObject service = services.getJSONObject(i); + String serviceName = service.getString("name"); + String className = service.getString("class"); + registerService(registry, serviceName, className); + } + } catch (FileNotFoundException e) { + // Not all apps will have a services.json file. + return; + } catch (Exception e) { + Log.e(TAG, "Failure parsing service configuration file", e); + return; + } + } + + /** + * Registers a third-party service. + */ + private static void registerService(ServiceRegistry registry, final String serviceName, final String className) { + registry.register(serviceName, new ServiceFactory() { + @Override + public void connectToService(Context context, Core core, MessagePipeHandle pipe) { + try { + Class.forName(className) + .getMethod("connectToService", Context.class, Core.class, MessagePipeHandle.class) + .invoke(null, context, core, pipe); + } catch(Exception e) { + Log.e(TAG, "Failed to register service '" + serviceName + "'", e); + } + } + }); + } + + private static void initJavaUtils(Context applicationContext) { + PathUtils.setPrivateDataDirectorySuffix(PRIVATE_DATA_DIRECTORY_SUFFIX, + applicationContext); + } + + private static void initResources(Context applicationContext) { + Context context = applicationContext; + new ResourceCleaner(context).start(); + sResourceExtractor = new ResourceExtractor(context); + sResourceExtractor.addResources(SKY_RESOURCES); + sResourceExtractor.start(); + } + + private static void initNative(Context applicationContext) { + try { + LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized(applicationContext); + } catch (ProcessInitException e) { + Log.e(TAG, "Unable to load Sky Engine binary.", e); + throw new RuntimeException(e); + } + } }