Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4899e386 authored by Bjorn Bringert's avatar Bjorn Bringert
Browse files

Move global search intent launching to search dialog

parent aa0e47cb
Loading
Loading
Loading
Loading
+128 −10
Original line number Diff line number Diff line
@@ -34,7 +34,10 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Browser;
import android.server.search.SearchableInfo;
import android.speech.RecognizerIntent;
import android.text.Editable;
@@ -42,6 +45,7 @@ import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.util.Regex;
import android.util.AndroidRuntimeException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextThemeWrapper;
@@ -1093,7 +1097,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
     */
    protected void launchQuerySearch(int actionKey, String actionMsg)  {
        String query = mSearchAutoComplete.getText().toString();
        Intent intent = createIntent(Intent.ACTION_SEARCH, null, null, query, null,
        String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
        Intent intent = createIntent(action, null, null, query, null,
                actionKey, actionMsg);
        launchIntent(intent);
    }
@@ -1245,14 +1250,125 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
            return;
        }
        Log.d(LOG_TAG, "launching " + intent);
        try {
            // in global search mode, we send the activity straight to the original suggestion
            // source. this is because GlobalSearch may not have permission to launch the
            // intent, and to avoid the extra step of going through GlobalSearch.
            if (mGlobalSearchMode) {
                launchGlobalSearchIntent(intent);
            } else {
                getContext().startActivity(intent);

        // in global search mode, SearchDialogWrapper#performActivityResuming will handle hiding
        // the dialog when the next activity starts, but for in-app search, we still need to
        // dismiss the dialog.
        if (!mGlobalSearchMode) {
                // in global search mode, SearchDialogWrapper#performActivityResuming
                // will handle hiding the dialog when the next activity starts, but for
                // in-app search, we still need to dismiss the dialog.
                dismiss();
            }
        } catch (RuntimeException ex) {
            Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
        }
    }

    private void launchGlobalSearchIntent(Intent intent) {
        final String packageName;
        // GlobalSearch puts the original source of the suggestion in the
        // 'component name' column. If set, we send the intent to that activity.
        // We trust GlobalSearch to always set this to the suggestion source.
        String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY);
        if (intentComponent != null) {
            ComponentName componentName = ComponentName.unflattenFromString(intentComponent);
            intent.setComponent(componentName);
            intent.removeExtra(SearchManager.COMPONENT_NAME_KEY);
            // Launch the intent as the suggestion source.
            // This prevents sources from using the search dialog to launch
            // intents that they don't have permission for themselves.
            packageName = componentName.getPackageName();
        } else {
            // If there is no component in the suggestion, it must be a built-in suggestion
            // from GlobalSearch (e.g. "Search the web for") or the intent
            // launched when pressing the search/go button in the search dialog.
            // Launch the intent with the permissions of GlobalSearch.
            packageName = mSearchable.getSearchActivity().getPackageName();
        }

        // Launch all global search suggestions as new tasks, since they don't relate
        // to the current task.
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        setBrowserApplicationId(intent);

        if (DBG) Log.d(LOG_TAG, "Launching intent " + intent.toURI() + " as " + packageName);
        startActivityInPackage(intent, packageName);
    }

    /**
     * If the intent is to open an HTTP or HTTPS URL, we set
     * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that
     * has been opened by us for the same URL will be reused.
     */
    private void setBrowserApplicationId(Intent intent) {
        Uri data = intent.getData();
        if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) {
            String scheme = data.getScheme();
            if (scheme != null && scheme.startsWith("http")) {
                intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString());
            }
        }
    }

    /**
     * Starts an activity as if it had been started by the given package.
     *
     * @param intent The description of the activity to start.
     * @param packageName
     * @throws ActivityNotFoundException If the intent could not be resolved to
     *         and existing activity.
     * @throws SecurityException If the package does not have permission to start
     *         start the activity.
     * @throws AndroidRuntimeException If some other error occurs.
     */
    private void startActivityInPackage(Intent intent, String packageName) {
        try {
            int uid = ActivityThread.getPackageManager().getPackageUid(packageName);
            if (uid < 0) {
                throw new AndroidRuntimeException("Package UID not found " + packageName);
            }
            String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
            IBinder resultTo = null;
            String resultWho = null;
            int requestCode = -1;
            boolean onlyIfNeeded = false;
            int result = ActivityManagerNative.getDefault().startActivityInPackage(
                    uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded);
            checkStartActivityResult(result, intent);
        } catch (RemoteException ex) {
            throw new AndroidRuntimeException(ex);
        }
    }

    // Stolen from Instrumentation.checkStartActivityResult()
    private static void checkStartActivityResult(int res, Intent intent) {
        if (res >= IActivityManager.START_SUCCESS) {
            return;
        }
        switch (res) {
            case IActivityManager.START_INTENT_NOT_RESOLVED:
            case IActivityManager.START_CLASS_NOT_FOUND:
                if (intent.getComponent() != null)
                    throw new ActivityNotFoundException(
                            "Unable to find explicit activity class "
                            + intent.getComponent().toShortString()
                            + "; have you declared this activity in your AndroidManifest.xml?");
                throw new ActivityNotFoundException(
                        "No Activity found to handle " + intent);
            case IActivityManager.START_PERMISSION_DENIED:
                throw new SecurityException("Not allowed to start activity "
                        + intent);
            case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                throw new AndroidRuntimeException(
                        "FORWARD_RESULT_FLAG used while also requesting a result");
            default:
                throw new AndroidRuntimeException("Unknown error code "
                        + res + " when starting " + intent);
        }
    }

    /**
@@ -1460,8 +1576,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
            intent.putExtra(SearchManager.ACTION_KEY, actionKey);
            intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
        }
        // attempt to enforce security requirement (no 3rd-party intents)
        // Only allow 3rd-party intents from GlobalSearch
        if (!mGlobalSearchMode) {
            intent.setComponent(mSearchable.getSearchActivity());
        }
        return intent;
    }