public static GeckoEvent createIMESelectEvent(int start, int end) {
   GeckoEvent event = new GeckoEvent(IME_EVENT);
   event.mAction = IME_SET_SELECTION;
   event.mStart = start;
   event.mEnd = end;
   return event;
 }
  /* Informs Gecko that the screen size has changed. */
  private void sendResizeEventIfNecessary(boolean force) {
    DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();

    IntSize newScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
    IntSize newWindowSize = new IntSize(mView.getWidth(), mView.getHeight());

    boolean screenSizeChanged = !mScreenSize.equals(newScreenSize);
    boolean windowSizeChanged = !mWindowSize.equals(newWindowSize);

    if (!force && !screenSizeChanged && !windowSizeChanged) {
      return;
    }

    mScreenSize = newScreenSize;
    mWindowSize = newWindowSize;

    if (screenSizeChanged) {
      Log.d(LOGTAG, "Screen-size changed to " + mScreenSize);
    }

    if (windowSizeChanged) {
      Log.d(LOGTAG, "Window-size changed to " + mWindowSize);
    }

    GeckoEvent event =
        GeckoEvent.createSizeChangedEvent(
            mWindowSize.width, mWindowSize.height,
            mScreenSize.width, mScreenSize.height);
    GeckoAppShell.sendEventToGecko(event);
    GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Window:Resize", ""));
  }
 public static GeckoEvent createScreenshotEvent(
     int tabId,
     int sx,
     int sy,
     int sw,
     int sh,
     int dx,
     int dy,
     int dw,
     int dh,
     int bw,
     int bh,
     int token,
     ByteBuffer buffer) {
   GeckoEvent event = new GeckoEvent(SCREENSHOT);
   event.mPoints = new Point[5];
   event.mPoints[0] = new Point(sx, sy);
   event.mPoints[1] = new Point(sw, sh);
   event.mPoints[2] = new Point(dx, dy);
   event.mPoints[3] = new Point(dw, dh);
   event.mPoints[4] = new Point(bw, bh);
   event.mMetaState = tabId;
   event.mFlags = token;
   event.mBuffer = buffer;
   return event;
 }
 public static GeckoEvent createSizeChangedEvent(int w, int h, int screenw, int screenh) {
   GeckoEvent event = new GeckoEvent(SIZE_CHANGED);
   event.mPoints = new Point[2];
   event.mPoints[0] = new Point(w, h);
   event.mPoints[1] = new Point(screenw, screenh);
   return event;
 }
 public static GeckoEvent createIMECompositionEvent(int start, int end) {
   GeckoEvent event = new GeckoEvent(IME_EVENT);
   event.mAction = IME_UPDATE_COMPOSITION;
   event.mStart = start;
   event.mEnd = end;
   return event;
 }
  // Run all queued methods
  private static void flushQueuedNativeCallsLocked(final State state) {
    int lastSkipped = -1;
    for (int i = 0; i < QUEUED_CALLS.size(); i++) {
      final QueuedCall call = QUEUED_CALLS.get(i);
      if (call == null) {
        // We already handled the call.
        continue;
      }
      if (!state.isAtLeast(call.state)) {
        // The call is not ready yet; skip it.
        lastSkipped = i;
        continue;
      }
      // Mark as handled.
      QUEUED_CALLS.set(i, null);

      if (call.method == null) {
        final GeckoEvent e = (GeckoEvent) call.target;
        GeckoAppShell.notifyGeckoOfEvent(e);
        e.recycle();
        continue;
      }
      invokeMethod(call.method, call.target, call.args);
    }
    if (lastSkipped < 0) {
      // We're done here; release the memory
      QUEUED_CALLS.clear();
      QUEUED_CALLS.trimToSize();
    } else if (lastSkipped < QUEUED_CALLS.size() - 1) {
      // We skipped some; free up null entries at the end,
      // but keep all the previous entries for later.
      QUEUED_CALLS.subList(lastSkipped + 1, QUEUED_CALLS.size()).clear();
    }
  }
  /** Restore default search engines in Gecko and retrigger a search engine refresh. */
  protected void restoreDefaultSearchEngines() {
    GeckoAppShell.sendEventToGecko(
        GeckoEvent.createBroadcastEvent("SearchEngines:RestoreDefaults", null));

    // Send message to Gecko to get engines. SearchPreferenceCategory listens for the response.
    GeckoAppShell.sendEventToGecko(
        GeckoEvent.createBroadcastEvent("SearchEngines:GetVisible", null));
  }
 public static GeckoEvent createIMEReplaceEvent(int start, int end, String text) {
   GeckoEvent event = new GeckoEvent(IME_EVENT);
   event.mAction = IME_REPLACE_TEXT;
   event.mStart = start;
   event.mEnd = end;
   event.mCharacters = text;
   return event;
 }
  private boolean processKeyDown(int keyCode, KeyEvent event, boolean isPreIme) {
    if (DEBUG) {
      Log.d(
          LOGTAG,
          "IME: processKeyDown(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")");
    }

    clampSelection();

    switch (keyCode) {
      case KeyEvent.KEYCODE_MENU:
      case KeyEvent.KEYCODE_BACK:
      case KeyEvent.KEYCODE_VOLUME_UP:
      case KeyEvent.KEYCODE_VOLUME_DOWN:
      case KeyEvent.KEYCODE_SEARCH:
        return false;
      case KeyEvent.KEYCODE_DEL:
        // See comments in GeckoInputConnection.onKeyDel
        if (onKeyDel()) {
          return true;
        }
        break;
      case KeyEvent.KEYCODE_ENTER:
        if ((event.getFlags() & KeyEvent.FLAG_EDITOR_ACTION) != 0
            && mIMEActionHint.equalsIgnoreCase("next"))
          event = new KeyEvent(event.getAction(), KeyEvent.KEYCODE_TAB);
        break;
      default:
        break;
    }

    if (isPreIme
        && mIMEState != IME_STATE_DISABLED
        && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0)
      // Let active IME process pre-IME key events
      return false;

    View view = GeckoApp.mAppContext.getLayerController().getView();
    KeyListener keyListener = TextKeyListener.getInstance();

    // KeyListener returns true if it handled the event for us.
    if (mIMEState == IME_STATE_DISABLED
        || keyCode == KeyEvent.KEYCODE_ENTER
        || keyCode == KeyEvent.KEYCODE_DEL
        || keyCode == KeyEvent.KEYCODE_TAB
        || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0
        || !keyListener.onKeyDown(view, mEditable, keyCode, event)) {
      // Make sure selection in Gecko is up-to-date
      final Editable content = getEditable();
      int a = Selection.getSelectionStart(content);
      int b = Selection.getSelectionEnd(content);
      GeckoAppShell.sendEventToGecko(
          GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, a, b - a));

      GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event));
    }
    return true;
  }
  private boolean processKeyUp(int keyCode, KeyEvent event, boolean isPreIme) {
    if (DEBUG) {
      Log.d(
          LOGTAG,
          "IME: processKeyUp(keyCode=" + keyCode + ", event=" + event + ", " + isPreIme + ")");
    }

    switch (keyCode) {
      case KeyEvent.KEYCODE_BACK:
      case KeyEvent.KEYCODE_SEARCH:
      case KeyEvent.KEYCODE_MENU:
        return false;
      default:
        break;
    }

    if (isPreIme
        && mIMEState != IME_STATE_DISABLED
        && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0)
      // Let active IME process pre-IME key events
      return false;

    View view = GeckoApp.mAppContext.getLayerController().getView();
    KeyListener keyListener = TextKeyListener.getInstance();

    if (mIMEState == IME_STATE_DISABLED
        || keyCode == KeyEvent.KEYCODE_ENTER
        || keyCode == KeyEvent.KEYCODE_DEL
        || (event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0
        || !keyListener.onKeyUp(view, mEditable, keyCode, event)) {
      GeckoAppShell.sendEventToGecko(GeckoEvent.createKeyEvent(event));
    }

    return true;
  }
  boolean scrollBy(PointF displacement) {
    if (!mOverridePanning) {
      return false;
    }

    if (!mOverrideScrollAck) {
      mOverrideScrollPending = true;
      mPendingDisplacement.x += displacement.x;
      mPendingDisplacement.y += displacement.y;
      return true;
    }

    JSONObject json = new JSONObject();
    try {
      json.put("x", displacement.x);
      json.put("y", displacement.y);
    } catch (JSONException e) {
      Log.e(LOGTAG, "Error forming subwindow scroll message: ", e);
    }
    GeckoAppShell.sendEventToGecko(
        GeckoEvent.createBroadcastEvent(MESSAGE_SCROLL, json.toString()));

    mOverrideScrollAck = false;
    mOverrideScrollPending = false;
    // clear the |mPendingDisplacement| after serializing |displacement| to
    // JSON because they might be the same object
    mPendingDisplacement.x = 0;
    mPendingDisplacement.y = 0;

    return true;
  }
  /*
   * DoorHanger.OnButtonClickListener implementation
   */
  @Override
  public void onButtonClick(DoorHanger dh, String tag) {
    JSONObject response = new JSONObject();
    try {
      response.put("callback", tag);

      CheckBox checkBox = dh.getCheckBox();
      // If the checkbox is being used, pass its value
      if (checkBox != null) {
        response.put("checked", checkBox.isChecked());
      }

      List<PromptInput> doorHangerInputs = dh.getInputs();
      if (doorHangerInputs != null) {
        JSONObject inputs = new JSONObject();
        for (PromptInput input : doorHangerInputs) {
          inputs.put(input.getId(), input.getValue());
        }
        response.put("inputs", inputs);
      }
    } catch (JSONException e) {
      Log.e(LOGTAG, "Error creating onClick response", e);
    }

    GeckoEvent e = GeckoEvent.createBroadcastEvent("Doorhanger:Reply", response.toString());
    GeckoAppShell.sendEventToGecko(e);
    removeDoorHanger(dh);
    updatePopup();
  }
  @Override
  public boolean setSelection(int start, int end) {
    GeckoAppShell.sendEventToGecko(
        GeckoEvent.createIMEEvent(GeckoEvent.IME_SET_SELECTION, start, end - start));

    return super.setSelection(start, end);
  }
  /** Send current network state and connection type as a GeckoEvent, to whomever is listening. */
  private void sendNetworkStateToListeners() {
    final Context applicationContext = GeckoAppShell.getApplicationContext();
    final GeckoEvent networkEvent =
        GeckoEvent.createNetworkEvent(
            currentConnectionType.value,
            currentConnectionType == ConnectionType.WIFI,
            wifiDhcpGatewayAddress(applicationContext),
            currentConnectionSubtype.value);
    final GeckoEvent networkLinkChangeValueEvent =
        GeckoEvent.createNetworkLinkChangeEvent(currentNetworkStatus.value);
    final GeckoEvent networkLinkChangeNotificationEvent =
        GeckoEvent.createNetworkLinkChangeEvent(LINK_DATA_CHANGED);

    GeckoAppShell.sendEventToGecko(networkEvent);
    GeckoAppShell.sendEventToGecko(networkLinkChangeValueEvent);
    GeckoAppShell.sendEventToGecko(networkLinkChangeNotificationEvent);
  }
 public static GeckoEvent createViewportEvent(
     ImmutableViewportMetrics metrics, DisplayPortMetrics displayPort) {
   GeckoEvent event = new GeckoEvent(VIEWPORT);
   event.mCharacters = "Viewport:Change";
   StringBuffer sb = new StringBuffer(256);
   sb.append("{ \"x\" : ")
       .append(metrics.viewportRectLeft)
       .append(", \"y\" : ")
       .append(metrics.viewportRectTop)
       .append(", \"zoom\" : ")
       .append(metrics.zoomFactor)
       .append(", \"displayPort\" :")
       .append(displayPort.toJSON())
       .append('}');
   event.mCharactersExtra = sb.toString();
   return event;
 }
Exemple #16
0
  public AllPagesTab(Context context) {
    super(context);
    mSearchEngines = new ArrayList<SearchEngine>();

    registerEventListener("SearchEngines:Data");
    GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("SearchEngines:Get", null));

    mHandler = new AllPagesHandler();
  }
Exemple #17
0
  @Override
  public void requestZoomedViewRender() {
    if (stopUpdateView) {
      return;
    }
    // remove pending runnable
    ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);

    // "requestZoomedViewRender" can be called very often by Gecko (endDrawing in LayerRender)
    // without
    // any thing changed in the zoomed area (useless calls from the "zoomed area" point of view).
    // "requestZoomedViewRender" can take time to re-render the zoomed view, it depends of the
    // complexity
    // of the html on this area.
    // To avoid to slow down the application, the 2 following cases are tested:

    // 1- Last render is still running, plan another render later.
    if (isRendering()) {
      // post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later
      // We need to post with a delay to be sure that the last call to requestZoomedViewRender will
      // be done.
      // For a static html page WITHOUT any animation/video, there is a last call to endDrawing and
      // we need to make
      // the zoomed render on this last call.
      ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS);
      return;
    }

    // 2- Current render occurs too early, plan another render later.
    if (renderFrequencyTooHigh()) {
      // post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later
      // We need to post with a delay to be sure that the last call to requestZoomedViewRender will
      // be done.
      // For a page WITH animation/video, the animation/video can be stopped, and we need to make
      // the zoomed render on this last call.
      ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS);
      return;
    }

    startTimeReRender = System.nanoTime();
    // Allocate the buffer if it's the first call.
    // Change the buffer size if it's not the right size.
    updateBufferSize();

    int tabId = Tabs.getInstance().getSelectedTab().getId();

    ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
    PointF origin = metrics.getOrigin();

    final int xPos = (int) origin.x + lastPosition.x;
    final int yPos = (int) origin.y + lastPosition.y;

    GeckoEvent e =
        GeckoEvent.createZoomedViewEvent(
            tabId, xPos, yPos, viewWidth, viewHeight, zoomFactor * metrics.zoomFactor, buffer);
    GeckoAppShell.sendEventToGecko(e);
  }
 public void finishDialog(String aReturn) {
   mInputs = null;
   mButtons = null;
   mDialog = null;
   mSelected = null;
   mPromptQueue.offer(aReturn);
   // poke the Gecko thread in case it's waiting for new events
   GeckoAppShell.sendEventToGecko(GeckoEvent.createNoOpEvent());
 }
Exemple #19
0
 private void connectToGecko() {
   GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning);
   Tab selectedTab = Tabs.getInstance().getSelectedTab();
   if (selectedTab != null)
     Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED);
   geckoConnected();
   GeckoAppShell.setLayerClient(getLayerClientObject());
   GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
 }
Exemple #20
0
 /**
  * Handle a confirmation response from the user.
  *
  * @param value String value to return to the browser context.
  */
 public void confirmWithValue(String value) {
   JSONObject result = makeResult(RESULT_OK);
   try {
     result.put("textbox0", value);
   } catch (JSONException ex) {
   }
   GeckoAppShell.sendEventToGecko(
       GeckoEvent.createBroadcastEvent("Prompt:Reply", result.toString()));
 }
Exemple #21
0
 @Override
 public void onClick(View v) {
   switch (v.getId()) {
     case R.id.find_prev:
       GeckoAppShell.sendEventToGecko(
           GeckoEvent.createBroadcastEvent("FindInPage:Prev", mFindText.getText().toString()));
       getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0);
       break;
     case R.id.find_next:
       GeckoAppShell.sendEventToGecko(
           GeckoEvent.createBroadcastEvent("FindInPage:Next", mFindText.getText().toString()));
       getInputMethodManager(mFindText).hideSoftInputFromWindow(mFindText.getWindowToken(), 0);
       break;
     case R.id.find_close:
       hide();
       break;
   }
 }
 public static GeckoEvent createIMERangeEvent(
     int start, int end, int rangeType, int rangeStyles, int rangeForeColor, int rangeBackColor) {
   GeckoEvent event = new GeckoEvent(IME_EVENT);
   event.mAction = IME_ADD_COMPOSITION_RANGE;
   event.mStart = start;
   event.mEnd = end;
   event.mRangeType = rangeType;
   event.mRangeStyles = rangeStyles;
   event.mRangeForeColor = rangeForeColor;
   event.mRangeBackColor = rangeBackColor;
   return event;
 }
 /** Implementation of LayerView.Listener */
 public void compositionResumeRequested(int width, int height) {
   // Asking Gecko to resume the compositor takes too long (see
   // https://bugzilla.mozilla.org/show_bug.cgi?id=735230#c23), so we
   // resume the compositor directly. We still need to inform Gecko about
   // the compositor resuming, so that Gecko knows that it can now draw.
   if (mCompositorCreated) {
     GeckoAppShell.scheduleResumeComposition(width, height);
     GeckoAppShell.sendEventToGecko(GeckoEvent.createCompositorResumeEvent());
   }
 }
  protected void onActivityResume(GeckoActivityStatus activity) {
    if (mPausedGecko) {
      GeckoAppShell.sendEventToGecko(GeckoEvent.createAppForegroundingEvent());
      mPausedGecko = false;
    }
    GeckoConnectivityReceiver.getInstance().start();
    GeckoNetworkManager.getInstance().start();

    mInBackground = false;
  }
Exemple #25
0
  public void handleNotificationIntent(Intent i) {
    final Uri data = i.getData();
    if (data == null) {
      Log.e(LOGTAG, "handleNotificationEvent: empty data");
      return;
    }
    final String id = data.getQueryParameter(ID_ATTR);
    final String notificationType = data.getQueryParameter(EVENT_TYPE_ATTR);
    if (id == null || notificationType == null) {
      Log.e(LOGTAG, "handleNotificationEvent: invalid intent parameters");
      return;
    }

    // In case the user swiped out the notification, we empty the id set.
    if (CLEARED_EVENT.equals(notificationType)) {
      mClearableNotifications.remove(id);
      // If Gecko isn't running, we throw away events where the notification was cancelled.
      // i.e. Don't bug the user if they're just closing a bunch of notifications.
      if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
        return;
      }
    }

    JSONObject args = new JSONObject();

    // The handler and cookie parameters are optional
    final String handler = data.getQueryParameter(HANDLER_ATTR);
    final String cookie = i.getStringExtra(COOKIE_ATTR);

    try {
      args.put(ID_ATTR, id);
      args.put(EVENT_TYPE_ATTR, notificationType);
      args.put(HANDLER_ATTR, handler);
      args.put(COOKIE_ATTR, cookie);

      if (BUTTON_EVENT.equals(notificationType)) {
        final String actionName = data.getQueryParameter(ACTION_ID_ATTR);
        args.put(ACTION_ID_ATTR, actionName);
      }

      Log.i(LOGTAG, "Send " + args.toString());
      GeckoAppShell.sendEventToGecko(
          GeckoEvent.createBroadcastEvent("Notification:Event", args.toString()));
    } catch (JSONException e) {
      Log.e(LOGTAG, "Error building JSON notification arguments.", e);
    }

    // If the notification was clicked, we are closing it. This must be executed after
    // sending the event to js side because when the notification is canceled no event can be
    // handled.
    if (CLICK_EVENT.equals(notificationType) && !i.getBooleanExtra(ONGOING_ATTR, false)) {
      hideNotification(id, handler, cookie);
    }
  }
 public static void addPendingEvent(final GeckoEvent e) {
   synchronized (QUEUED_CALLS) {
     if (isRunning()) {
       // We may just have switched to running state.
       GeckoAppShell.notifyGeckoOfEvent(e);
       e.recycle();
     } else {
       QUEUED_CALLS.add(new QueuedCall(null, e, null, State.RUNNING));
     }
   }
 }
 @Override
 public boolean onActionItemClicked(ActionModeCompat mode, MenuItem item) {
   try {
     final JSONObject obj = mItems.getJSONObject(item.getItemId());
     GeckoAppShell.sendEventToGecko(
         GeckoEvent.createBroadcastEvent("TextSelection:Action", obj.optString("id")));
     return true;
   } catch (Exception ex) {
     Log.i(LOGTAG, "Exception calling action", ex);
   }
   return false;
 }
Exemple #28
0
 /**
  * Load a URL resource into the Browser.
  *
  * @param url The URL string.
  */
 public void loadUrl(String url) {
   JSONObject args = new JSONObject();
   try {
     args.put("url", url);
     args.put("parentId", -1);
     args.put("newTab", false);
     args.put("tabID", mId);
   } catch (Exception e) {
     Log.w(LOGTAG, "Error building JSON arguments for loadUrl.", e);
   }
   GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
 }
  private void updateNetworkType() {
    NetworkType previousNetworkType = mNetworkType;
    mNetworkType = getNetworkType();

    if (mNetworkType == previousNetworkType || !mShouldNotify) {
      return;
    }

    GeckoAppShell.sendEventToGecko(
        GeckoEvent.createNetworkEvent(
            getNetworkSpeed(mNetworkType), isNetworkUsuallyMetered(mNetworkType)));
  }
 /** Implementation of LayerView.Listener */
 public void compositionPauseRequested() {
   // We need to coordinate with Gecko when pausing composition, to ensure
   // that Gecko never executes a draw event while the compositor is paused.
   // This is sent synchronously to make sure that we don't attempt to use
   // any outstanding Surfaces after we call this (such as from a
   // surfaceDestroyed notification), and to make sure that any in-flight
   // Gecko draw events have been processed.  When this returns, composition is
   // definitely paused -- it'll synchronize with the Gecko event loop, which
   // in turn will synchronize with the compositor thread.
   if (mCompositorCreated) {
     GeckoAppShell.sendEventToGeckoSync(GeckoEvent.createCompositorPauseEvent());
   }
 }