Commit 8b0efe23 authored by Zac McKenney's avatar Zac McKenney
Browse files

Bug 1781780: Only add exported activities to handle intent ACTION_PROCESS_TEXT...

Bug 1781780: Only add exported activities to handle intent ACTION_PROCESS_TEXT in floating toolbar menu. r=geckoview-reviewers,owlish

Differential Revision: https://phabricator.services.mozilla.com/D166222
parent 469fad0e
Loading
Loading
Loading
Loading
+65 −21
Original line number Diff line number Diff line
@@ -9,8 +9,10 @@ package org.mozilla.geckoview;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
@@ -26,6 +28,8 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import java.util.ArrayList;
import java.util.List;
import org.mozilla.gecko.util.ThreadUtils;

/**
@@ -178,12 +182,33 @@ public class BasicSelectionActionDelegate
    }

    if (mExternalActionsEnabled && !mSelection.text.isEmpty() && ACTION_PROCESS_TEXT.equals(id)) {
      final PackageManager pm = mActivity.getPackageManager();
      return pm.resolveActivity(getProcessTextIntent(), PackageManager.MATCH_DEFAULT_ONLY) != null;
      return !getProcessTextExportedActivities().isEmpty();
    }

    return mSelection.isActionAvailable(id);
  }

  /**
   * Get exported activities for {@link BasicSelectionActionDelegate#ACTION_PROCESS_TEXT} when text
   * is selected.
   *
   * @return list of exported activities
   */
  private @NonNull List<ResolveInfo> getProcessTextExportedActivities() {
    final PackageManager pm = mActivity.getPackageManager();
    final List<ResolveInfo> resolvedList =
        pm.queryIntentActivityOptions(
            null, null, getProcessTextIntent(null), PackageManager.MATCH_DEFAULT_ONLY);
    final ArrayList<ResolveInfo> exportedList = new ArrayList<>();
    for (final ResolveInfo info : resolvedList) {
      if (info.activityInfo.exported) {
        exportedList.add(info);
      }
    }

    return exportedList;
  }

  /**
   * Provides access to whether there are text selection actions available. Override to indicate
   * availability for custom actions.
@@ -302,8 +327,12 @@ public class BasicSelectionActionDelegate
    return mSelection.text.substring(0, maxLength);
  }

  private Intent getProcessTextIntent() {
  private Intent getProcessTextIntent(@Nullable final ResolveInfo resolveInfo) {
    final Intent intent = new Intent(Intent.ACTION_PROCESS_TEXT);
    if (resolveInfo != null) {
      intent.setComponent(
          new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name));
    }
    intent.addCategory(Intent.CATEGORY_DEFAULT);
    intent.setType("text/plain");
    // If using large text, anything intent may throw RemoteException.
@@ -345,24 +374,14 @@ public class BasicSelectionActionDelegate
      final int menuId = i + Menu.FIRST;

      if (ACTION_PROCESS_TEXT.equals(actionId)) {
        if (mExternalActionsEnabled && !mSelection.text.isEmpty()) {
          try {
            menu.addIntentOptions(
                menuId,
                menuId,
                menuId,
                mActivity.getComponentName(),
                /* specifiec */ null,
                getProcessTextIntent(),
                /* flags */ 0, /* items */
                null);
        if (mExternalActionsEnabled && mSelection != null && !mSelection.text.isEmpty()) {
          final List<ResolveInfo> exportedPackageInfo = getProcessTextExportedActivities();
          if (!exportedPackageInfo.isEmpty()) {
            for (final ResolveInfo info : exportedPackageInfo) {
              final boolean isMenuItemAdded = addProcessTextMenuItem(menu, menuId, info);
              if (isMenuItemAdded) {
                changed = true;
          } catch (final RuntimeException e) {
            if (e.getCause() instanceof TransactionTooLargeException) {
              // Binder size error. MAX_INTENT_TEXT_LENGTH is still large?
              Log.e(LOGTAG, "Cannot add intent option", e);
            } else {
              throw e;
              }
            }
          }
        } else if (menu.findItem(menuId) != null) {
@@ -385,6 +404,31 @@ public class BasicSelectionActionDelegate
    return changed;
  }

  private boolean addProcessTextMenuItem(
      final Menu menu, final int menuId, final ResolveInfo info) {
    boolean isMenuItemAdded = false;
    try {
      menu.addIntentOptions(
          menuId,
          menuId,
          menuId,
          mActivity.getComponentName(),
          /* specifiec */ null,
          getProcessTextIntent(info),
          /* flags */ Menu.FLAG_APPEND_TO_GROUP, /* items */
          null);
      isMenuItemAdded = true;
    } catch (final RuntimeException e) {
      if (e.getCause() instanceof TransactionTooLargeException) {
        // Binder size error. MAX_INTENT_TEXT_LENGTH is still large?
        Log.e(LOGTAG, "Cannot add intent option", e);
      } else {
        throw e;
      }
    }
    return isMenuItemAdded;
  }

  @Override
  public boolean onActionItemClicked(final ActionMode actionMode, final MenuItem menuItem) {
    ThreadUtils.assertOnUiThread();