build/mobile/robocop/FennecNativeActions.java

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 package org.mozilla.gecko;
michael@0 6
michael@0 7 import java.util.concurrent.BlockingQueue;
michael@0 8 import java.util.concurrent.LinkedBlockingQueue;
michael@0 9 import java.util.concurrent.TimeUnit;
michael@0 10
michael@0 11 import org.json.JSONObject;
michael@0 12 import org.mozilla.gecko.FennecNativeDriver.LogLevel;
michael@0 13 import org.mozilla.gecko.gfx.LayerView;
michael@0 14 import org.mozilla.gecko.gfx.LayerView.DrawListener;
michael@0 15 import org.mozilla.gecko.mozglue.GeckoLoader;
michael@0 16 import org.mozilla.gecko.sqlite.SQLiteBridge;
michael@0 17 import org.mozilla.gecko.util.GeckoEventListener;
michael@0 18
michael@0 19 import android.app.Activity;
michael@0 20 import android.app.Instrumentation;
michael@0 21 import android.database.Cursor;
michael@0 22 import android.os.SystemClock;
michael@0 23 import android.text.TextUtils;
michael@0 24 import android.view.KeyEvent;
michael@0 25
michael@0 26 import com.jayway.android.robotium.solo.Solo;
michael@0 27
michael@0 28 public class FennecNativeActions implements Actions {
michael@0 29 private static final String LOGTAG = "FennecNativeActions";
michael@0 30
michael@0 31 private Solo mSolo;
michael@0 32 private Instrumentation mInstr;
michael@0 33 private Assert mAsserter;
michael@0 34
michael@0 35 public FennecNativeActions(Activity activity, Solo robocop, Instrumentation instrumentation, Assert asserter) {
michael@0 36 mSolo = robocop;
michael@0 37 mInstr = instrumentation;
michael@0 38 mAsserter = asserter;
michael@0 39
michael@0 40 GeckoLoader.loadSQLiteLibs(activity, activity.getApplication().getPackageResourcePath());
michael@0 41 }
michael@0 42
michael@0 43 class GeckoEventExpecter implements RepeatedEventExpecter {
michael@0 44 private static final int MAX_WAIT_MS = 90000;
michael@0 45
michael@0 46 private volatile boolean mIsRegistered;
michael@0 47
michael@0 48 private final String mGeckoEvent;
michael@0 49 private final GeckoEventListener mListener;
michael@0 50
michael@0 51 private volatile boolean mEventEverReceived;
michael@0 52 private String mEventData;
michael@0 53 private BlockingQueue<String> mEventDataQueue;
michael@0 54
michael@0 55 GeckoEventExpecter(final String geckoEvent) {
michael@0 56 if (TextUtils.isEmpty(geckoEvent)) {
michael@0 57 throw new IllegalArgumentException("geckoEvent must not be empty");
michael@0 58 }
michael@0 59
michael@0 60 mGeckoEvent = geckoEvent;
michael@0 61 mEventDataQueue = new LinkedBlockingQueue<String>();
michael@0 62
michael@0 63 final GeckoEventExpecter expecter = this;
michael@0 64 mListener = new GeckoEventListener() {
michael@0 65 @Override
michael@0 66 public void handleMessage(final String event, final JSONObject message) {
michael@0 67 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
michael@0 68 "handleMessage called for: " + event + "; expecting: " + mGeckoEvent);
michael@0 69 mAsserter.is(event, mGeckoEvent, "Given message occurred for registered event: " + message);
michael@0 70
michael@0 71 expecter.notifyOfEvent(message);
michael@0 72 }
michael@0 73 };
michael@0 74
michael@0 75 GeckoAppShell.registerEventListener(mGeckoEvent, mListener);
michael@0 76 mIsRegistered = true;
michael@0 77 }
michael@0 78
michael@0 79 public void blockForEvent() {
michael@0 80 blockForEvent(MAX_WAIT_MS, true);
michael@0 81 }
michael@0 82
michael@0 83 public void blockForEvent(long millis, boolean failOnTimeout) {
michael@0 84 if (!mIsRegistered) {
michael@0 85 throw new IllegalStateException("listener not registered");
michael@0 86 }
michael@0 87
michael@0 88 try {
michael@0 89 mEventData = mEventDataQueue.poll(millis, TimeUnit.MILLISECONDS);
michael@0 90 } catch (InterruptedException ie) {
michael@0 91 FennecNativeDriver.log(LogLevel.ERROR, ie);
michael@0 92 }
michael@0 93 if (mEventData == null) {
michael@0 94 if (failOnTimeout) {
michael@0 95 FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
michael@0 96 mAsserter.ok(false, "GeckoEventExpecter",
michael@0 97 "blockForEvent timeout: "+mGeckoEvent);
michael@0 98 } else {
michael@0 99 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
michael@0 100 "blockForEvent timeout: "+mGeckoEvent);
michael@0 101 }
michael@0 102 } else {
michael@0 103 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
michael@0 104 "unblocked on expecter for " + mGeckoEvent);
michael@0 105 }
michael@0 106 }
michael@0 107
michael@0 108 public void blockUntilClear(long millis) {
michael@0 109 if (!mIsRegistered) {
michael@0 110 throw new IllegalStateException("listener not registered");
michael@0 111 }
michael@0 112 if (millis <= 0) {
michael@0 113 throw new IllegalArgumentException("millis must be > 0");
michael@0 114 }
michael@0 115
michael@0 116 // wait for at least one event
michael@0 117 try {
michael@0 118 mEventData = mEventDataQueue.poll(MAX_WAIT_MS, TimeUnit.MILLISECONDS);
michael@0 119 } catch (InterruptedException ie) {
michael@0 120 FennecNativeDriver.log(LogLevel.ERROR, ie);
michael@0 121 }
michael@0 122 if (mEventData == null) {
michael@0 123 FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
michael@0 124 mAsserter.ok(false, "GeckoEventExpecter", "blockUntilClear timeout");
michael@0 125 return;
michael@0 126 }
michael@0 127 // now wait for a period of millis where we don't get an event
michael@0 128 while (true) {
michael@0 129 try {
michael@0 130 mEventData = mEventDataQueue.poll(millis, TimeUnit.MILLISECONDS);
michael@0 131 } catch (InterruptedException ie) {
michael@0 132 FennecNativeDriver.log(LogLevel.INFO, ie);
michael@0 133 }
michael@0 134 if (mEventData == null) {
michael@0 135 // success
michael@0 136 break;
michael@0 137 }
michael@0 138 }
michael@0 139 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
michael@0 140 "unblocked on expecter for " + mGeckoEvent);
michael@0 141 }
michael@0 142
michael@0 143 public String blockForEventData() {
michael@0 144 blockForEvent();
michael@0 145 return mEventData;
michael@0 146 }
michael@0 147
michael@0 148 public String blockForEventDataWithTimeout(long millis) {
michael@0 149 blockForEvent(millis, false);
michael@0 150 return mEventData;
michael@0 151 }
michael@0 152
michael@0 153 public void unregisterListener() {
michael@0 154 if (!mIsRegistered) {
michael@0 155 throw new IllegalStateException("listener not registered");
michael@0 156 }
michael@0 157
michael@0 158 FennecNativeDriver.log(LogLevel.INFO,
michael@0 159 "EventExpecter: no longer listening for " + mGeckoEvent);
michael@0 160
michael@0 161 GeckoAppShell.unregisterEventListener(mGeckoEvent, mListener);
michael@0 162 mIsRegistered = false;
michael@0 163 }
michael@0 164
michael@0 165 public boolean eventReceived() {
michael@0 166 return mEventEverReceived;
michael@0 167 }
michael@0 168
michael@0 169 void notifyOfEvent(final JSONObject message) {
michael@0 170 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
michael@0 171 "received event " + mGeckoEvent);
michael@0 172
michael@0 173 mEventEverReceived = true;
michael@0 174
michael@0 175 try {
michael@0 176 mEventDataQueue.put(message.toString());
michael@0 177 } catch (InterruptedException e) {
michael@0 178 FennecNativeDriver.log(LogLevel.ERROR,
michael@0 179 "EventExpecter dropped event: " + message.toString(), e);
michael@0 180 }
michael@0 181 }
michael@0 182 }
michael@0 183
michael@0 184 public RepeatedEventExpecter expectGeckoEvent(final String geckoEvent) {
michael@0 185 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG, "waiting for " + geckoEvent);
michael@0 186 return new GeckoEventExpecter(geckoEvent);
michael@0 187 }
michael@0 188
michael@0 189 public void sendGeckoEvent(final String geckoEvent, final String data) {
michael@0 190 GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(geckoEvent, data));
michael@0 191 }
michael@0 192
michael@0 193 public void sendPreferencesGetEvent(int requestId, String[] prefNames) {
michael@0 194 GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesGetEvent(requestId, prefNames));
michael@0 195 }
michael@0 196
michael@0 197 public void sendPreferencesObserveEvent(int requestId, String[] prefNames) {
michael@0 198 GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesObserveEvent(requestId, prefNames));
michael@0 199 }
michael@0 200
michael@0 201 public void sendPreferencesRemoveObserversEvent(int requestId) {
michael@0 202 GeckoAppShell.sendEventToGecko(GeckoEvent.createPreferencesRemoveObserversEvent(requestId));
michael@0 203 }
michael@0 204
michael@0 205 class PaintExpecter implements RepeatedEventExpecter {
michael@0 206 private static final int MAX_WAIT_MS = 90000;
michael@0 207
michael@0 208 private boolean mPaintDone;
michael@0 209 private boolean mListening;
michael@0 210
michael@0 211 private final LayerView mLayerView;
michael@0 212 private final DrawListener mDrawListener;
michael@0 213
michael@0 214 PaintExpecter() {
michael@0 215 final PaintExpecter expecter = this;
michael@0 216 mLayerView = GeckoAppShell.getLayerView();
michael@0 217 mDrawListener = new DrawListener() {
michael@0 218 @Override
michael@0 219 public void drawFinished() {
michael@0 220 FennecNativeDriver.log(FennecNativeDriver.LogLevel.DEBUG,
michael@0 221 "Received drawFinished notification");
michael@0 222 expecter.notifyOfEvent();
michael@0 223 }
michael@0 224 };
michael@0 225 mLayerView.addDrawListener(mDrawListener);
michael@0 226 mListening = true;
michael@0 227 }
michael@0 228
michael@0 229 private synchronized void notifyOfEvent() {
michael@0 230 mPaintDone = true;
michael@0 231 this.notifyAll();
michael@0 232 }
michael@0 233
michael@0 234 public synchronized void blockForEvent(long millis, boolean failOnTimeout) {
michael@0 235 if (!mListening) {
michael@0 236 throw new IllegalStateException("draw listener not registered");
michael@0 237 }
michael@0 238 long startTime = SystemClock.uptimeMillis();
michael@0 239 long endTime = 0;
michael@0 240 while (!mPaintDone) {
michael@0 241 try {
michael@0 242 this.wait(millis);
michael@0 243 } catch (InterruptedException ie) {
michael@0 244 FennecNativeDriver.log(LogLevel.ERROR, ie);
michael@0 245 break;
michael@0 246 }
michael@0 247 endTime = SystemClock.uptimeMillis();
michael@0 248 if (!mPaintDone && (endTime - startTime >= millis)) {
michael@0 249 if (failOnTimeout) {
michael@0 250 FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
michael@0 251 mAsserter.ok(false, "PaintExpecter", "blockForEvent timeout");
michael@0 252 }
michael@0 253 return;
michael@0 254 }
michael@0 255 }
michael@0 256 }
michael@0 257
michael@0 258 public synchronized void blockForEvent() {
michael@0 259 blockForEvent(MAX_WAIT_MS, true);
michael@0 260 }
michael@0 261
michael@0 262 public synchronized String blockForEventData() {
michael@0 263 blockForEvent();
michael@0 264 return null;
michael@0 265 }
michael@0 266
michael@0 267 public synchronized String blockForEventDataWithTimeout(long millis) {
michael@0 268 blockForEvent(millis, false);
michael@0 269 return null;
michael@0 270 }
michael@0 271
michael@0 272 public synchronized boolean eventReceived() {
michael@0 273 return mPaintDone;
michael@0 274 }
michael@0 275
michael@0 276 public synchronized void blockUntilClear(long millis) {
michael@0 277 if (!mListening) {
michael@0 278 throw new IllegalStateException("draw listener not registered");
michael@0 279 }
michael@0 280 if (millis <= 0) {
michael@0 281 throw new IllegalArgumentException("millis must be > 0");
michael@0 282 }
michael@0 283 // wait for at least one event
michael@0 284 long startTime = SystemClock.uptimeMillis();
michael@0 285 long endTime = 0;
michael@0 286 while (!mPaintDone) {
michael@0 287 try {
michael@0 288 this.wait(MAX_WAIT_MS);
michael@0 289 } catch (InterruptedException ie) {
michael@0 290 FennecNativeDriver.log(LogLevel.ERROR, ie);
michael@0 291 break;
michael@0 292 }
michael@0 293 endTime = SystemClock.uptimeMillis();
michael@0 294 if (!mPaintDone && (endTime - startTime >= MAX_WAIT_MS)) {
michael@0 295 FennecNativeDriver.logAllStackTraces(FennecNativeDriver.LogLevel.ERROR);
michael@0 296 mAsserter.ok(false, "PaintExpecter", "blockUtilClear timeout");
michael@0 297 return;
michael@0 298 }
michael@0 299 }
michael@0 300 // now wait for a period of millis where we don't get an event
michael@0 301 startTime = SystemClock.uptimeMillis();
michael@0 302 while (true) {
michael@0 303 try {
michael@0 304 this.wait(millis);
michael@0 305 } catch (InterruptedException ie) {
michael@0 306 FennecNativeDriver.log(LogLevel.ERROR, ie);
michael@0 307 break;
michael@0 308 }
michael@0 309 endTime = SystemClock.uptimeMillis();
michael@0 310 if (endTime - startTime >= millis) {
michael@0 311 // success
michael@0 312 break;
michael@0 313 }
michael@0 314
michael@0 315 // we got a notify() before we could wait long enough, so we need to start over
michael@0 316 // Note, moving the goal post might have us race against a "drawFinished" flood
michael@0 317 startTime = endTime;
michael@0 318 }
michael@0 319 }
michael@0 320
michael@0 321 public synchronized void unregisterListener() {
michael@0 322 if (!mListening) {
michael@0 323 throw new IllegalStateException("listener not registered");
michael@0 324 }
michael@0 325
michael@0 326 FennecNativeDriver.log(LogLevel.INFO,
michael@0 327 "PaintExpecter: no longer listening for events");
michael@0 328 mLayerView.removeDrawListener(mDrawListener);
michael@0 329 mListening = false;
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 public RepeatedEventExpecter expectPaint() {
michael@0 334 return new PaintExpecter();
michael@0 335 }
michael@0 336
michael@0 337 public void sendSpecialKey(SpecialKey button) {
michael@0 338 switch(button) {
michael@0 339 case DOWN:
michael@0 340 sendKeyCode(KeyEvent.KEYCODE_DPAD_DOWN);
michael@0 341 break;
michael@0 342 case UP:
michael@0 343 sendKeyCode(KeyEvent.KEYCODE_DPAD_UP);
michael@0 344 break;
michael@0 345 case LEFT:
michael@0 346 sendKeyCode(KeyEvent.KEYCODE_DPAD_LEFT);
michael@0 347 break;
michael@0 348 case RIGHT:
michael@0 349 sendKeyCode(KeyEvent.KEYCODE_DPAD_RIGHT);
michael@0 350 break;
michael@0 351 case ENTER:
michael@0 352 sendKeyCode(KeyEvent.KEYCODE_ENTER);
michael@0 353 break;
michael@0 354 case MENU:
michael@0 355 sendKeyCode(KeyEvent.KEYCODE_MENU);
michael@0 356 break;
michael@0 357 case BACK:
michael@0 358 sendKeyCode(KeyEvent.KEYCODE_BACK);
michael@0 359 break;
michael@0 360 default:
michael@0 361 mAsserter.ok(false, "sendSpecialKey", "Unknown SpecialKey " + button);
michael@0 362 break;
michael@0 363 }
michael@0 364 }
michael@0 365
michael@0 366 public void sendKeyCode(int keyCode) {
michael@0 367 if (keyCode <= 0 || keyCode > KeyEvent.getMaxKeyCode()) {
michael@0 368 mAsserter.ok(false, "sendKeyCode", "Unknown keyCode " + keyCode);
michael@0 369 }
michael@0 370 mInstr.sendCharacterSync(keyCode);
michael@0 371 }
michael@0 372
michael@0 373 @Override
michael@0 374 public void sendKeys(String input) {
michael@0 375 mInstr.sendStringSync(input);
michael@0 376 }
michael@0 377
michael@0 378 public void drag(int startingX, int endingX, int startingY, int endingY) {
michael@0 379 mSolo.drag(startingX, endingX, startingY, endingY, 10);
michael@0 380 }
michael@0 381
michael@0 382 public Cursor querySql(final String dbPath, final String sql) {
michael@0 383 return new SQLiteBridge(dbPath).rawQuery(sql, null);
michael@0 384 }
michael@0 385 }

mercurial