Bug 938827 - Part 10: Remove remaining reflection from FennecNativeActions. r=rnewman

This commit is contained in:
Michael Comella 2013-12-06 11:43:12 -08:00
parent be30179d74
commit 2660081718
5 changed files with 31 additions and 122 deletions

View File

@ -5,6 +5,8 @@
package org.mozilla.gecko;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.GeckoLayerClient.DrawListener;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.sqlite.SQLiteBridge;
import org.mozilla.gecko.util.GeckoEventListener;
@ -20,10 +22,6 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@ -35,39 +33,18 @@ import com.jayway.android.robotium.solo.Solo;
import static org.mozilla.gecko.FennecNativeDriver.LogLevel;
public class FennecNativeActions implements Actions {
private static final String LOGTAG = "FennecNativeActions";
private Solo mSolo;
private Instrumentation mInstr;
private Assert mAsserter;
// Objects for reflexive access of fennec classes.
private ClassLoader mClassLoader;
private Class mApiClass;
private Class mDrawListenerClass;
private Method mSetDrawListener;
private Object mRobocopApi;
private static final String LOGTAG = "FennecNativeActions";
public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation, Assert asserter) {
mSolo = robocop;
mInstr = instrumentation;
mAsserter = asserter;
GeckoLoader.loadSQLiteLibs(activity, activity.getApplication().getPackageResourcePath());
// Set up reflexive access of java classes and methods.
try {
mClassLoader = activity.getClassLoader();
mApiClass = mClassLoader.loadClass("org.mozilla.gecko.RobocopAPI");
mDrawListenerClass = mClassLoader.loadClass("org.mozilla.gecko.gfx.GeckoLayerClient$DrawListener");
mSetDrawListener = mApiClass.getMethod("setDrawListener", mDrawListenerClass);
mRobocopApi = mApiClass.getConstructor(Activity.class).newInstance(activity);
} catch (Exception e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
}
class GeckoEventExpecter implements RepeatedEventExpecter {
@ -232,46 +209,31 @@ public class FennecNativeActions implements Actions {
GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesRemoveObserversEvent(requestId));
}
class DrawListenerProxy implements InvocationHandler {
private final PaintExpecter mPaintExpecter;
DrawListenerProxy(PaintExpecter paintExpecter) {
mPaintExpecter = paintExpecter;
}
public Object invoke(Object proxy, Method method, Object[] args) {
String methodName = method.getName();
if ("drawFinished".equals(methodName)) {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"Received drawFinished notification");
mPaintExpecter.notifyOfEvent(args);
} else if ("toString".equals(methodName)) {
return "DrawListenerProxy";
} else if ("equals".equals(methodName)) {
return false;
} else if ("hashCode".equals(methodName)) {
return 0;
}
return null;
}
}
class PaintExpecter implements RepeatedEventExpecter {
private boolean mPaintDone;
private boolean mListening;
private static final int MAX_WAIT_MS = 90000;
PaintExpecter() throws IllegalAccessException, InvocationTargetException {
Object proxy = Proxy.newProxyInstance(mClassLoader, new Class[] { mDrawListenerClass }, new DrawListenerProxy(this));
mSetDrawListener.invoke(mRobocopApi, proxy);
private boolean mPaintDone;
private boolean mListening;
private final GeckoLayerClient mLayerClient;
PaintExpecter() {
final PaintExpecter expecter = this;
mLayerClient = GeckoAppShell.getLayerView().getLayerClient();
mLayerClient.setDrawListener(new DrawListener() {
@Override
public void drawFinished() {
FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
"Received drawFinished notification");
expecter.notifyOfEvent();
}
});
mListening = true;
}
void notifyOfEvent(Object[] args) {
synchronized (this) {
mPaintDone = true;
this.notifyAll();
}
private synchronized void notifyOfEvent() {
mPaintDone = true;
this.notifyAll();
}
private synchronized void blockForEvent(long millis, boolean failOnTimeout) {
@ -365,23 +327,16 @@ public class FennecNativeActions implements Actions {
if (!mListening) {
throw new IllegalStateException("listener not registered");
}
try {
FennecNativeDriver.log(LogLevel.INFO, "PaintExpecter: no longer listening for events");
mListening = false;
mSetDrawListener.invoke(mRobocopApi, (Object)null);
} catch (Exception e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
}
FennecNativeDriver.log(LogLevel.INFO,
"PaintExpecter: no longer listening for events");
mLayerClient.setDrawListener(null);
mListening = false;
}
}
public RepeatedEventExpecter expectPaint() {
try {
return new PaintExpecter();
} catch (Exception e) {
FennecNativeDriver.log(LogLevel.ERROR, e);
return null;
}
return new PaintExpecter();
}
public void sendSpecialKey(SpecialKey button) {

View File

@ -325,6 +325,7 @@ public class GeckoAppShell
sLayerView = lv;
}
@RobocopTarget
public static LayerView getLayerView() {
return sLayerView;
}

View File

@ -1,47 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.GeckoEventListener;
import android.app.Activity;
import android.database.Cursor;
import android.view.View;
import java.nio.IntBuffer;
import java.util.List;
/**
* Class to provide wrapper methods around methods wanted by Robocop.
*
* This class provides fixed entry points into code that is liable to be optimised by Proguard without
* needing to prevent Proguard from optimising the wrapped methods.
* Wrapping in this way still slightly hinders Proguard's ability to optimise.
*
* If you find yourself wanting to add a method to this class - proceed with caution. If you're writing
* a test that's not about manipulating the UI, you might be better off using JUnit (Or similar)
* instead of Robocop.
*
* Alternatively, you might be able to get what you want by reflecting on a method annotated for the
* benefit of the C++ wrapper generator - these methods are sure to not disappear at compile-time.
*
* Finally, you might be able to get what you want via Reflection on Android's libraries. Those are
* also not prone to vanishing at compile-time, but doing this might substantially complicate your
* work, ultimately not proving worth the extra effort to avoid making a slight mess here.
*/
@RobocopTarget
public class RobocopAPI {
private final GeckoApp mGeckoApp;
public RobocopAPI(Activity activity) {
mGeckoApp = (GeckoApp)activity;
}
public void setDrawListener(GeckoLayerClient.DrawListener listener) {
GeckoAppShell.getLayerView().getLayerClient().setDrawListener(listener);
}
}

View File

@ -325,6 +325,7 @@ public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener
}
}
@RobocopTarget
public GeckoLayerClient getLayerClient() { return mLayerClient; }
public PanZoomController getPanZoomController() { return mPanZoomController; }
public LayerMarginsAnimator getLayerMarginsAnimator() { return mMarginsAnimator; }

View File

@ -273,7 +273,6 @@ gbjar.sources += [
'ReferrerReceiver.java',
'RemoteTabs.java',
'Restarter.java',
'RobocopAPI.java',
'ScrollAnimator.java',
'ServiceNotificationClient.java',
'SessionParser.java',