am cb37e715: Refactoring plugins to use new java interfaces.

Merge commit 'cb37e71509da43e0d8d809591b09e8f5a582b5cd' into eclair-mr2-plus-aosp

* commit 'cb37e71509da43e0d8d809591b09e8f5a582b5cd':
  Refactoring plugins to use new java interfaces.
This commit is contained in:
Derek Sollenberger
2009-11-30 07:55:59 -08:00
committed by Android Git Automerger
7 changed files with 287 additions and 108 deletions

View File

@@ -19,6 +19,8 @@ import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.webkit.plugin.SurfaceDrawingModel;
import android.webkit.plugin.WebkitPlugin;
/** /**
* This activity is invoked when a plugin elects to go into full screen mode. * This activity is invoked when a plugin elects to go into full screen mode.
@@ -28,8 +30,6 @@ public class PluginActivity extends Activity {
/* package */ static final String INTENT_EXTRA_PACKAGE_NAME = /* package */ static final String INTENT_EXTRA_PACKAGE_NAME =
"android.webkit.plugin.PACKAGE_NAME"; "android.webkit.plugin.PACKAGE_NAME";
/* package */ static final String INTENT_EXTRA_CLASS_NAME =
"android.webkit.plugin.CLASS_NAME";
/* package */ static final String INTENT_EXTRA_NPP_INSTANCE = /* package */ static final String INTENT_EXTRA_NPP_INSTANCE =
"android.webkit.plugin.NPP_INSTANCE"; "android.webkit.plugin.NPP_INSTANCE";
@@ -42,25 +42,31 @@ public class PluginActivity extends Activity {
if (intent == null) { if (intent == null) {
// No intent means no class to lookup. // No intent means no class to lookup.
finish(); finish();
return;
} }
final String packageName = final String pkgName = intent.getStringExtra(INTENT_EXTRA_PACKAGE_NAME);
intent.getStringExtra(INTENT_EXTRA_PACKAGE_NAME);
final String className = intent.getStringExtra(INTENT_EXTRA_CLASS_NAME);
final int npp = intent.getIntExtra(INTENT_EXTRA_NPP_INSTANCE, -1); final int npp = intent.getIntExtra(INTENT_EXTRA_NPP_INSTANCE, -1);
// Retrieve the PluginStub implemented in packageName.className
PluginStub stub =
PluginUtil.getPluginStub(this, packageName, className);
if (stub != null) { // XXX retrieve the existing object instead of creating a new one
View pluginView = stub.getFullScreenView(npp, this); WebkitPlugin plugin = PluginManager.getInstance(null).getPluginInstance(pkgName, npp);
if (pluginView != null) {
setContentView(pluginView); if (plugin == null) {
} else { //TODO log error
// No custom full-sreen view returned by the plugin, odd but finish();
// just in case, finish the activity. return;
finish(); }
} SurfaceDrawingModel fullScreenSurface = plugin.getFullScreenSurface();
if(fullScreenSurface == null) {
//TODO log error
finish();
return;
}
View pluginView = fullScreenSurface.getSurface();
if (pluginView != null) {
setContentView(pluginView);
} else { } else {
// No custom full-sreen view returned by the plugin, odd but
// just in case, finish the activity.
finish(); finish();
} }
} }

View File

@@ -31,6 +31,8 @@ import android.content.pm.Signature;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.util.Log; import android.util.Log;
import android.webkit.plugin.NativePlugin;
import android.webkit.plugin.WebkitPlugin;
/** /**
* Class for managing the relationship between the {@link WebView} and installed * Class for managing the relationship between the {@link WebView} and installed
@@ -41,6 +43,12 @@ import android.util.Log;
*/ */
public class PluginManager { public class PluginManager {
private class PluginInfo {
public PackageInfo packageInfo;
public boolean isNative;
public Class<? extends WebkitPlugin> pluginClass;
}
/** /**
* Service Action: A plugin wishes to be loaded in the WebView must provide * Service Action: A plugin wishes to be loaded in the WebView must provide
* {@link android.content.IntentFilter IntentFilter} that accepts this * {@link android.content.IntentFilter IntentFilter} that accepts this
@@ -60,11 +68,14 @@ public class PluginManager {
private static final String LOGTAG = "webkit"; private static final String LOGTAG = "webkit";
private static final String PLUGIN_TYPE = "type";
private static final String TYPE_NATIVE = "native";
private static PluginManager mInstance = null; private static PluginManager mInstance = null;
private final Context mContext; private final Context mContext;
private ArrayList<PackageInfo> mPackageInfoCache; private ArrayList<PluginInfo> mPluginInfoCache;
// Only plugin matches one of the signatures in the list can be loaded // Only plugin matches one of the signatures in the list can be loaded
// inside the WebView process // inside the WebView process
@@ -76,7 +87,7 @@ public class PluginManager {
private PluginManager(Context context) { private PluginManager(Context context) {
mContext = context; mContext = context;
mPackageInfoCache = new ArrayList<PackageInfo>(); mPluginInfoCache = new ArrayList<PluginInfo>();
} }
public static synchronized PluginManager getInstance(Context context) { public static synchronized PluginManager getInstance(Context context) {
@@ -108,35 +119,44 @@ public class PluginManager {
ArrayList<String> directories = new ArrayList<String>(); ArrayList<String> directories = new ArrayList<String>();
PackageManager pm = mContext.getPackageManager(); PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> plugins = pm.queryIntentServices(new Intent( List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
PLUGIN_ACTION), PackageManager.GET_SERVICES); PLUGIN_ACTION), PackageManager.GET_SERVICES
| PackageManager.GET_META_DATA);
synchronized(mPackageInfoCache) { synchronized(mPluginInfoCache) {
// clear the list of existing packageInfo objects // clear the list of existing packageInfo objects
mPackageInfoCache.clear(); mPluginInfoCache.clear();
for (ResolveInfo info : plugins) { for (ResolveInfo info : plugins) {
// retrieve the plugin's service information
ServiceInfo serviceInfo = info.serviceInfo; ServiceInfo serviceInfo = info.serviceInfo;
if (serviceInfo == null) { if (serviceInfo == null) {
Log.w(LOGTAG, "Ignore bad plugin"); Log.w(LOGTAG, "Ignore bad plugin");
continue; continue;
} }
// retrieve information from the plugin's manifest
PackageInfo pkgInfo; PackageInfo pkgInfo;
try { try {
pkgInfo = pm.getPackageInfo(serviceInfo.packageName, pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
PackageManager.GET_PERMISSIONS PackageManager.GET_PERMISSIONS
| PackageManager.GET_SIGNATURES); | PackageManager.GET_SIGNATURES);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName); Log.w(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
continue; continue;
} }
if (pkgInfo == null) { if (pkgInfo == null) {
continue; continue;
} }
// check if their is a conflict in the lib directory names
String directory = pkgInfo.applicationInfo.dataDir + "/lib"; String directory = pkgInfo.applicationInfo.dataDir + "/lib";
if (directories.contains(directory)) { if (directories.contains(directory)) {
continue; continue;
} }
// check if the plugin has the required permissions
String permissions[] = pkgInfo.requestedPermissions; String permissions[] = pkgInfo.requestedPermissions;
if (permissions == null) { if (permissions == null) {
continue; continue;
@@ -151,6 +171,8 @@ public class PluginManager {
if (!permissionOk) { if (!permissionOk) {
continue; continue;
} }
// check to ensure the plugin is properly signed
Signature signatures[] = pkgInfo.signatures; Signature signatures[] = pkgInfo.signatures;
if (signatures == null) { if (signatures == null) {
continue; continue;
@@ -169,7 +191,51 @@ public class PluginManager {
continue; continue;
} }
} }
mPackageInfoCache.add(pkgInfo);
PluginInfo pluginInfo = new PluginInfo();
pluginInfo.packageInfo = pkgInfo;
// determine the type of plugin from the manifest
if (serviceInfo.metaData == null) {
Log.e(LOGTAG, "The plugin '" + serviceInfo.name + "' has no type defined");
continue;
}
String pluginType = serviceInfo.metaData.getString(PLUGIN_TYPE);
if (TYPE_NATIVE.equals(pluginType)) {
pluginInfo.isNative = true;
} else {
Log.e(LOGTAG, "Unrecognized plugin type: " + pluginType);
continue;
}
try {
Class<?> cls = getPluginClass(serviceInfo.packageName, serviceInfo.name);
boolean classFound = false;
for(Class<?> implemented : cls.getInterfaces()) {
if (pluginInfo.isNative && implemented.equals(NativePlugin.class)) {
pluginInfo.pluginClass = cls.asSubclass(WebkitPlugin.class);
classFound = true;
break;
}
}
if (!classFound) {
Log.e(LOGTAG, "The plugin's class'" + serviceInfo.name + "' does not extend the appropriate interface.");
continue;
}
} catch (NameNotFoundException e) {
Log.e(LOGTAG, "Can't find plugin: " + serviceInfo.packageName);
continue;
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "Can't find plugin's class: " + serviceInfo.name);
continue;
}
// if all checks have passed then make the plugin available
mPluginInfoCache.add(pluginInfo);
directories.add(directory); directories.add(directory);
} }
} }
@@ -177,6 +243,7 @@ public class PluginManager {
return directories.toArray(new String[directories.size()]); return directories.toArray(new String[directories.size()]);
} }
/* package */
String getPluginsAPKName(String pluginLib) { String getPluginsAPKName(String pluginLib) {
// basic error checking on input params // basic error checking on input params
@@ -185,8 +252,9 @@ public class PluginManager {
} }
// must be synchronized to ensure the consistency of the cache // must be synchronized to ensure the consistency of the cache
synchronized(mPackageInfoCache) { synchronized(mPluginInfoCache) {
for (PackageInfo pkgInfo : mPackageInfoCache) { for (PluginInfo pluginInfo : mPluginInfoCache) {
PackageInfo pkgInfo = pluginInfo.packageInfo;
if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) { if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) {
return pkgInfo.packageName; return pkgInfo.packageName;
} }
@@ -200,4 +268,47 @@ public class PluginManager {
String getPluginSharedDataDirectory() { String getPluginSharedDataDirectory() {
return mContext.getDir("plugins", 0).getPath(); return mContext.getDir("plugins", 0).getPath();
} }
/* package */
WebkitPlugin getPluginInstance(String pkgName, int npp) {
// must be synchronized to ensure the consistency of the cache
synchronized(mPluginInfoCache) {
// lookup plugin based on pkgName and instantiate if possible.
for (PluginInfo pluginInfo : mPluginInfoCache) {
if (pluginInfo.packageInfo.packageName.equals(pkgName)) {
try {
WebkitPlugin webkitPlugin = pluginInfo.pluginClass.newInstance();
if (pluginInfo.isNative) {
NativePlugin nativePlugin = (NativePlugin) webkitPlugin;
nativePlugin.initializePlugin(npp, mContext);
}
return webkitPlugin;
} catch (Exception e) {
// Any number of things could have happened. Log the exception and
// return null. Careful not to use Log.e(LOGTAG, "String", e)
// because that reports the exception to the checkin service.
Log.e(LOGTAG, Log.getStackTraceString(e));
}
break;
}
}
}
return null;
}
/* package */
Class<?> getPluginClass(String packageName, String className)
throws NameNotFoundException, ClassNotFoundException {
Context pluginContext = mContext.createPackageContext(packageName,
Context.CONTEXT_INCLUDE_CODE |
Context.CONTEXT_IGNORE_SECURITY);
ClassLoader pluginCL = pluginContext.getClassLoader();
return pluginCL.loadClass(className);
}
} }

View File

@@ -1,61 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
class PluginUtil {
private static final String LOGTAG = "PluginUtil";
/**
*
* @param packageName the name of the apk where the class can be found
* @param className the fully qualified name of a subclass of PluginStub
*/
/* package */
static PluginStub getPluginStub(Context context, String packageName,
String className) {
try {
Class<?> stubClass = getPluginClass(context, packageName, className);
Object stubObject = stubClass.newInstance();
if (stubObject instanceof PluginStub) {
return (PluginStub) stubObject;
} else {
Log.e(LOGTAG, "The plugin class is not of type PluginStub");
}
} catch (Exception e) {
// Any number of things could have happened. Log the exception and
// return null. Careful not to use Log.e(LOGTAG, "String", e)
// because that reports the exception to the checkin service.
Log.e(LOGTAG, Log.getStackTraceString(e));
}
return null;
}
/* package */
static Class<?> getPluginClass(Context context, String packageName,
String className) throws NameNotFoundException, ClassNotFoundException {
Context pluginContext = context.createPackageContext(packageName,
Context.CONTEXT_INCLUDE_CODE |
Context.CONTEXT_IGNORE_SECURITY);
ClassLoader pluginCL = pluginContext.getClassLoader();
return pluginCL.loadClass(className);
}
}

View File

@@ -41,6 +41,8 @@ import android.view.KeyEvent;
import android.view.SurfaceHolder; import android.view.SurfaceHolder;
import android.view.SurfaceView; import android.view.SurfaceView;
import android.view.View; import android.view.View;
import android.webkit.plugin.SurfaceDrawingModel;
import android.webkit.plugin.WebkitPlugin;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@@ -2175,15 +2177,16 @@ final class WebViewCore {
return null; return null;
} }
String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName); PluginManager pluginManager = PluginManager.getInstance(null);
String pkgName = pluginManager.getPluginsAPKName(libName);
if (pkgName == null) { if (pkgName == null) {
Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
return null; return null;
} }
Class<?> pluginClass = null;
try { try {
pluginClass = PluginUtil.getPluginClass(mWebView.getContext(), pkgName, clsName); return pluginManager.getPluginClass(pkgName, clsName);
} catch (NameNotFoundException e) { } catch (NameNotFoundException e) {
Log.e(LOGTAG, "Unable to find plugin classloader for the apk (" + pkgName + ")"); Log.e(LOGTAG, "Unable to find plugin classloader for the apk (" + pkgName + ")");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
@@ -2191,12 +2194,29 @@ final class WebViewCore {
") in the apk (" + pkgName + ")"); ") in the apk (" + pkgName + ")");
} }
return pluginClass; return null;
}
private WebkitPlugin createPluginJavaInstance(String libName, int npp) {
if (mWebView == null) {
return null;
}
PluginManager pluginManager = PluginManager.getInstance(null);
String pkgName = pluginManager.getPluginsAPKName(libName);
if (pkgName == null) {
Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
return null;
}
return pluginManager.getPluginInstance(pkgName, npp);
} }
// called by JNI. PluginWidget function to launch an activity and overlays // called by JNI. PluginWidget function to launch an activity and overlays
// the activity with the View provided by the plugin class. // the activity with the View provided by the plugin class.
private void startFullScreenPluginActivity(String libName, String clsName, int npp) { private void startFullScreenPluginActivity(String libName, int npp) {
if (mWebView == null) { if (mWebView == null) {
return; return;
} }
@@ -2209,33 +2229,26 @@ final class WebViewCore {
Intent intent = new Intent("android.intent.webkit.PLUGIN"); Intent intent = new Intent("android.intent.webkit.PLUGIN");
intent.putExtra(PluginActivity.INTENT_EXTRA_PACKAGE_NAME, pkgName); intent.putExtra(PluginActivity.INTENT_EXTRA_PACKAGE_NAME, pkgName);
intent.putExtra(PluginActivity.INTENT_EXTRA_CLASS_NAME, clsName);
intent.putExtra(PluginActivity.INTENT_EXTRA_NPP_INSTANCE, npp); intent.putExtra(PluginActivity.INTENT_EXTRA_NPP_INSTANCE, npp);
mWebView.getContext().startActivity(intent); mWebView.getContext().startActivity(intent);
} }
// called by JNI. PluginWidget functions for creating an embedded View for // called by JNI. PluginWidget functions for creating an embedded View for
// the surface drawing model. // the surface drawing model.
private ViewManager.ChildView createSurface(String libName, String clsName, private ViewManager.ChildView createSurface(WebkitPlugin webkitPlugin,
int npp, int x, int y, int width, int height) { int x, int y, int width, int height) {
if (mWebView == null) { if (mWebView == null) {
return null; return null;
} }
String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName); SurfaceDrawingModel embeddedSurface = webkitPlugin.getEmbeddedSurface();
if (pkgName == null) { if(embeddedSurface == null) {
Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK"); Log.e(LOGTAG, "Attempted to create an embedded surface with a null drawing model");
return null; return null;
} }
PluginStub stub =PluginUtil.getPluginStub(mWebView.getContext(),pkgName, clsName); View pluginView = embeddedSurface.getSurface();
if (stub == null) {
Log.e(LOGTAG, "Unable to find plugin class (" + clsName +
") in the apk (" + pkgName + ")");
return null;
}
View pluginView = stub.getEmbeddedView(npp, mWebView.getContext());
ViewManager.ChildView view = mWebView.mViewManager.createView(); ViewManager.ChildView view = mWebView.mViewManager.createView();
view.mView = pluginView; view.mView = pluginView;

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2009, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package android.webkit.plugin;
import android.content.Context;
/**
*
* @hide pending API solidification
*/
public interface NativePlugin extends WebkitPlugin {
void initializePlugin(int npp, Context context);
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2009, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package android.webkit.plugin;
import android.view.View;
/**
*
* @hide pending API solidification
*/
public interface SurfaceDrawingModel {
public View getSurface();
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2009, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package android.webkit.plugin;
/**
*
* @hide pending API solidification
*/
public interface WebkitPlugin {
SurfaceDrawingModel getEmbeddedSurface();
SurfaceDrawingModel getFullScreenSurface();
}