Loading core/api/system-current.txt +21 −2 Original line number Diff line number Diff line Loading @@ -2288,10 +2288,29 @@ package android.app.contextualsearch { field @NonNull public static final android.os.Parcelable.Creator<android.app.contextualsearch.CallbackToken> CREATOR; } @FlaggedApi("android.app.contextualsearch.flags.config_parameters") public final class ContextualSearchConfig implements android.os.Parcelable { method public int describeContents(); method public int getDisplayId(); method @NonNull public android.os.Bundle getIntentExtras(); method @Nullable public android.graphics.Rect getSourceBounds(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.contextualsearch.ContextualSearchConfig> CREATOR; } public static final class ContextualSearchConfig.Builder { ctor public ContextualSearchConfig.Builder(); ctor public ContextualSearchConfig.Builder(@NonNull android.app.contextualsearch.ContextualSearchConfig); method @NonNull public android.app.contextualsearch.ContextualSearchConfig build(); method @NonNull public android.app.contextualsearch.ContextualSearchConfig.Builder setDisplayId(int); method @NonNull public android.app.contextualsearch.ContextualSearchConfig.Builder setIntentExtras(@Nullable android.os.Bundle); method @NonNull public android.app.contextualsearch.ContextualSearchConfig.Builder setSourceBounds(@Nullable android.graphics.Rect); } public final class ContextualSearchManager { method @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public boolean isContextualSearchAvailable(); method @FlaggedApi("android.app.contextualsearch.flags.config_parameters") public boolean isContextualSearchAvailable(); method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH) public void startContextualSearch(int); method @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public void startContextualSearch(); method @FlaggedApi("android.app.contextualsearch.flags.config_parameters") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH) public void startContextualSearch(int, @Nullable android.app.contextualsearch.ContextualSearchConfig); method @FlaggedApi("android.app.contextualsearch.flags.config_parameters") public void startContextualSearch(@NonNull android.app.Activity, @Nullable android.app.contextualsearch.ContextualSearchConfig); field public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH = "android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH"; field public static final int ENTRYPOINT_LONG_PRESS_HOME = 2; // 0x2 field public static final int ENTRYPOINT_LONG_PRESS_META = 10; // 0xa core/java/android/app/contextualsearch/ContextualSearchConfig.java 0 → 100644 +208 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.contextualsearch; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.contextualsearch.flags.Flags; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.view.Display; import java.util.Objects; /** * Configuration for Contextual Search invocations. Typically the parameters added here are passed * to the Contextual Search provider app as specified by the device configuration. * * @hide */ @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public final class ContextualSearchConfig implements Parcelable { private final int mDisplayId; @Nullable private final Rect mSourceBounds; @NonNull private final Bundle mIntentExtras; public static final @NonNull Creator<ContextualSearchConfig> CREATOR = new Creator<>() { @Override public ContextualSearchConfig createFromParcel(@NonNull Parcel in) { return new ContextualSearchConfig(in); } @Override public ContextualSearchConfig[] newArray(int size) { return new ContextualSearchConfig[size]; } }; ContextualSearchConfig(@NonNull Parcel in) { mDisplayId = in.readInt(); mSourceBounds = in.readTypedObject(Rect.CREATOR); mIntentExtras = Objects.requireNonNull( in.readBundle(ContextualSearchConfig.class.getClassLoader())); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mDisplayId); dest.writeTypedObject(mSourceBounds, flags); dest.writeBundle(mIntentExtras); } @Override public int describeContents() { return 0; } private ContextualSearchConfig(@NonNull Builder builder) { mDisplayId = builder.mDisplayId; mSourceBounds = builder.mSourceBounds; mIntentExtras = builder.mIntentExtras; } /** * @return The ID of the display where the search was triggered. This determines where the * screenshot is taken and displayed for user interaction. If the display ID is invalid, * the invocation will fail silently. If not specified, the system will use * {@link Display#DEFAULT_DISPLAY}, or the Activity's display if launched from an * Activity. */ public int getDisplayId() { return mDisplayId; } /** * @return The bounds of the source element that triggered the search, in screen coordinates. * Can be null if not available. */ @Nullable public Rect getSourceBounds() { return mSourceBounds == null ? null : new Rect(mSourceBounds); } /** * @return Extras to be added to the Intent sent to the Contextual Search app. These will be * merged with any other extras added to the Intent by ContextualSearchManagerService. */ @NonNull public Bundle getIntentExtras() { return new Bundle(mIntentExtras); } @Override public String toString() { return "ContextualSearchConfig{" + "mDisplayId=" + mDisplayId + ", " + "mSourceBounds=" + mSourceBounds + ", " + "mIntentExtras=" + mIntentExtras + '}'; } /** * Builder to create a {@link ContextualSearchConfig}. */ public static final class Builder { private int mDisplayId; @Nullable private Rect mSourceBounds; @NonNull private final Bundle mIntentExtras; /** * Creates a new Builder with default values. */ public Builder() { mDisplayId = Display.INVALID_DISPLAY; mSourceBounds = null; mIntentExtras = new Bundle(); } /** * Creates a new builder and initializes it with the values from the given * {@link ContextualSearchConfig}. * * @param config The config to copy values from. */ public Builder(@NonNull ContextualSearchConfig config) { mDisplayId = config.getDisplayId(); mSourceBounds = config.getSourceBounds(); mIntentExtras = config.getIntentExtras(); } /** * Sets the display ID for the contextual search invocation. * * @param displayId The ID of the display where the search was triggered. This determines * where the screenshot is taken and displayed for user interaction. If the * display ID is invalid, the invocation will fail silently. If not * specified, the system will use {@link Display#DEFAULT_DISPLAY}, or the * Activity's display if launched from an Activity. * @return This Builder object to allow for chaining of calls. */ @NonNull public Builder setDisplayId(int displayId) { mDisplayId = displayId; return this; } /** * Sets the source bounds for the contextual search invocation. * * @param sourceBounds The bounds of the source element that triggered the search, in screen * coordinates. Can be null if not available. * @return This Builder object to allow for chaining of calls. */ @NonNull public Builder setSourceBounds(@Nullable Rect sourceBounds) { mSourceBounds = sourceBounds == null ? null : new Rect(sourceBounds); return this; } /** * Sets any additional extras to be added to the intent sent to the Contextual Search app. * * @param intentExtras This will be merged with any other extras added to the intent by * ContextualSearchManagerService. To avoid having your extras * overwritten, prefix the keys with an agreed package name. * @return This Builder object to allow for chaining of calls. */ @NonNull public Builder setIntentExtras(@Nullable Bundle intentExtras) { mIntentExtras.clear(); if (intentExtras != null) { mIntentExtras.putAll(intentExtras); } return this; } /** * Builds the {@link ContextualSearchConfig} instance. * * @return The built {@link ContextualSearchConfig} object. */ @NonNull public ContextualSearchConfig build() { return new ContextualSearchConfig(this); } } } core/java/android/app/contextualsearch/ContextualSearchManager.java +77 −22 Original line number Diff line number Diff line Loading @@ -20,8 +20,11 @@ import static android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.Activity; import android.app.contextualsearch.flags.Flags; import android.content.Context; import android.os.IBinder; Loading @@ -29,19 +32,20 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.util.Log; import android.view.Display; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.Set; /** * {@link ContextualSearchManager} is a system service to facilitate contextual search experience on * configured Android devices. * <p> * This class lets a caller start contextual search by calling {@link #startContextualSearch} * method. * configured Android devices. This involves capturing screenshots that the Contextual Search system * app presents to the user for interaction, such as selecting content on the screenshot to get a * search result or take an action such as calling a phone number or translating text. * * @hide */ Loading Loading @@ -256,16 +260,18 @@ public final class ContextualSearchManager { } /** * Used to check whether contextual search is available on the device. This method should be * called before calling {@link #startContextualSearch()} or adding any UI related to it to * ensure that the device is configured to support contextual search. * Used to check whether contextual search is available on the device. If this method returns * {code false}, you should not add any UI related to this feature, nor call * {@link #startContextualSearch(Activity, ContextualSearchConfig)}. It's rare but possible that * the return value of this method will change in subsequent calls, e.g. if the Contextual * Search app is disabled or enabled by the user. * * @see #startContextualSearch() * @return true if contextual search is available on the device, false otherwise. * @see #startContextualSearch(Activity, ContextualSearchConfig) * @return {@code true} if contextual search is currently available, {@code false} otherwise * * @hide */ @FlaggedApi(Flags.FLAG_SELF_INVOCATION) @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public boolean isContextualSearchAvailable() { if (DEBUG) Log.d(TAG, "isContextualSearchAvailable"); Loading Loading @@ -295,20 +301,60 @@ public final class ContextualSearchManager { * <p>This method will fail silently if Contextual Search is not available on the device. * * @param entrypoint the invocation entrypoint * @throws SecurityException if the caller does not have the {@link ACCESS_CONTEXTUAL_SEARCH} * permission. * * @hide */ @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH) @SystemApi public void startContextualSearch(@Entrypoint int entrypoint) { if (DEBUG) Log.d(TAG, "startContextualSearch; entrypoint: " + entrypoint); startContextualSearchInternal(entrypoint, null); } /** * Used to start contextual search for a given system entrypoint. * <p> * When {@link #startContextualSearch} is called, the system server does the following: * <ul> * <li>Resolves the activity using the package name and intent filter. The package name * is fetched from the config specified in ContextualSearchManagerService. * The activity must have ACTION_LAUNCH_CONTEXTUAL_SEARCH specified in its manifest. * <li>Puts the required extras in the launch intent, which may include a * {@link android.media.projection.MediaProjection} session. * <li>Launches the activity. * </ul> * </p> * * <p>This method will fail silently if Contextual Search is not available on the device. * * @param entrypoint the invocation entrypoint * @param config the invocation configuration parameters. If {@code null}, default configuration * will be applied, including launching on {@link Display#DEFAULT_DISPLAY}. * * @hide */ @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH) @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public void startContextualSearch(@Entrypoint int entrypoint, @Nullable ContextualSearchConfig config) { startContextualSearchInternal(entrypoint, config); } /** * Internal method to start contextual search with an entrypoint and optional config. */ @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH) private void startContextualSearchInternal(@Entrypoint int entrypoint, @Nullable ContextualSearchConfig config) { if (!VALID_ENTRYPOINT_VALUES.contains(entrypoint)) { throw new IllegalArgumentException("Invalid entrypoint: " + entrypoint); } if (DEBUG) Log.d(TAG, "startContextualSearch for entrypoint: " + entrypoint); if (DEBUG) { Log.d(TAG, "startContextualSearch; entrypoint: " + entrypoint + "; config: " + config); } try { mService.startContextualSearch(entrypoint); mService.startContextualSearch(entrypoint, config); } catch (RemoteException e) { if (DEBUG) Log.d(TAG, "Failed to startContextualSearch", e); e.rethrowFromSystemServer(); Loading @@ -319,27 +365,36 @@ public final class ContextualSearchManager { * Used to start Contextual Search from within an app. This will send a screenshot to the * Contextual Search app designated by the device manufacturer. The user can then select content * on the screenshot to get a search result or take an action such as calling a phone number or * translating the text. * translating the text. Note that the screenshot will capture the full display and may include * content outside of your Activity, e.g. in split screen mode. * * <p>Prior to calling this method or showing any UI related to it, you should verify that * Contextual Search is available on the device by using {@link #isContextualSearchAvailable()}. * Otherwise, this method will fail silently. * * <p>This method should only be called from an app that has a foreground Activity. * <p>Note: The system will use the display ID of your activity unless a displayId is specified * in the config. This is strongly discouraged unless you have a specific reason to specify a * different display. * * @see #isContextualSearchAvailable() * @throws SecurityException if the caller does not have a foreground Activity. * @param activity your foreground Activity from which the search is started * @param config the invocation configuration parameters. If {@code null}, default configuration * will be applied, including launching the search on the same display as your * activity. * @throws SecurityException if the caller does not have a foreground Activity * * @hide */ @FlaggedApi(Flags.FLAG_SELF_INVOCATION) @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public void startContextualSearch() { if (DEBUG) Log.d(TAG, "startContextualSearch from app"); public void startContextualSearch(@NonNull Activity activity, @Nullable ContextualSearchConfig config) { Objects.requireNonNull(activity); if (DEBUG) Log.d(TAG, "startContextualSearchForActivity(" + activity + ", " + config + ")"); try { mService.startContextualSearchForForegroundApp(); mService.startContextualSearchForActivity(activity.getActivityToken(), config); } catch (RemoteException e) { if (DEBUG) Log.d(TAG, "Failed to startContextualSearch", e); if (DEBUG) Log.d(TAG, "Failed to startContextualSearchForActivity", e); e.rethrowFromSystemServer(); } } Loading core/java/android/app/contextualsearch/IContextualSearchManager.aidl +5 −2 Original line number Diff line number Diff line package android.app.contextualsearch; import android.app.contextualsearch.IContextualSearchCallback; parcelable ContextualSearchConfig; /** * @hide */ interface IContextualSearchManager { boolean isContextualSearchAvailable(); void startContextualSearchForForegroundApp(); oneway void startContextualSearch(int entrypoint); void startContextualSearchForActivity(in IBinder activityToken, in ContextualSearchConfig config); oneway void startContextualSearch(int entrypoint, in ContextualSearchConfig config); oneway void getContextualSearchState(in IBinder token, in IContextualSearchCallback callback); } core/java/android/app/contextualsearch/flags.aconfig +17 −14 Original line number Diff line number Diff line Loading @@ -51,9 +51,12 @@ flag { } flag { name: "self_invocation" name: "config_parameters" namespace: "sysui_integrations" description: "Enable apps to self-invoke Contextual Search." bug: "368653769" description: "Allow invocation parameters to be passed to Contextual Search, including from apps." bug: "371552433" is_exported: true metadata { purpose: PURPOSE_BUGFIX } } Loading
core/api/system-current.txt +21 −2 Original line number Diff line number Diff line Loading @@ -2288,10 +2288,29 @@ package android.app.contextualsearch { field @NonNull public static final android.os.Parcelable.Creator<android.app.contextualsearch.CallbackToken> CREATOR; } @FlaggedApi("android.app.contextualsearch.flags.config_parameters") public final class ContextualSearchConfig implements android.os.Parcelable { method public int describeContents(); method public int getDisplayId(); method @NonNull public android.os.Bundle getIntentExtras(); method @Nullable public android.graphics.Rect getSourceBounds(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.app.contextualsearch.ContextualSearchConfig> CREATOR; } public static final class ContextualSearchConfig.Builder { ctor public ContextualSearchConfig.Builder(); ctor public ContextualSearchConfig.Builder(@NonNull android.app.contextualsearch.ContextualSearchConfig); method @NonNull public android.app.contextualsearch.ContextualSearchConfig build(); method @NonNull public android.app.contextualsearch.ContextualSearchConfig.Builder setDisplayId(int); method @NonNull public android.app.contextualsearch.ContextualSearchConfig.Builder setIntentExtras(@Nullable android.os.Bundle); method @NonNull public android.app.contextualsearch.ContextualSearchConfig.Builder setSourceBounds(@Nullable android.graphics.Rect); } public final class ContextualSearchManager { method @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public boolean isContextualSearchAvailable(); method @FlaggedApi("android.app.contextualsearch.flags.config_parameters") public boolean isContextualSearchAvailable(); method @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH) public void startContextualSearch(int); method @FlaggedApi("android.app.contextualsearch.flags.self_invocation") public void startContextualSearch(); method @FlaggedApi("android.app.contextualsearch.flags.config_parameters") @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH) public void startContextualSearch(int, @Nullable android.app.contextualsearch.ContextualSearchConfig); method @FlaggedApi("android.app.contextualsearch.flags.config_parameters") public void startContextualSearch(@NonNull android.app.Activity, @Nullable android.app.contextualsearch.ContextualSearchConfig); field public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH = "android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH"; field public static final int ENTRYPOINT_LONG_PRESS_HOME = 2; // 0x2 field public static final int ENTRYPOINT_LONG_PRESS_META = 10; // 0xa
core/java/android/app/contextualsearch/ContextualSearchConfig.java 0 → 100644 +208 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.app.contextualsearch; import android.annotation.FlaggedApi; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.app.contextualsearch.flags.Flags; import android.graphics.Rect; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.view.Display; import java.util.Objects; /** * Configuration for Contextual Search invocations. Typically the parameters added here are passed * to the Contextual Search provider app as specified by the device configuration. * * @hide */ @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public final class ContextualSearchConfig implements Parcelable { private final int mDisplayId; @Nullable private final Rect mSourceBounds; @NonNull private final Bundle mIntentExtras; public static final @NonNull Creator<ContextualSearchConfig> CREATOR = new Creator<>() { @Override public ContextualSearchConfig createFromParcel(@NonNull Parcel in) { return new ContextualSearchConfig(in); } @Override public ContextualSearchConfig[] newArray(int size) { return new ContextualSearchConfig[size]; } }; ContextualSearchConfig(@NonNull Parcel in) { mDisplayId = in.readInt(); mSourceBounds = in.readTypedObject(Rect.CREATOR); mIntentExtras = Objects.requireNonNull( in.readBundle(ContextualSearchConfig.class.getClassLoader())); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mDisplayId); dest.writeTypedObject(mSourceBounds, flags); dest.writeBundle(mIntentExtras); } @Override public int describeContents() { return 0; } private ContextualSearchConfig(@NonNull Builder builder) { mDisplayId = builder.mDisplayId; mSourceBounds = builder.mSourceBounds; mIntentExtras = builder.mIntentExtras; } /** * @return The ID of the display where the search was triggered. This determines where the * screenshot is taken and displayed for user interaction. If the display ID is invalid, * the invocation will fail silently. If not specified, the system will use * {@link Display#DEFAULT_DISPLAY}, or the Activity's display if launched from an * Activity. */ public int getDisplayId() { return mDisplayId; } /** * @return The bounds of the source element that triggered the search, in screen coordinates. * Can be null if not available. */ @Nullable public Rect getSourceBounds() { return mSourceBounds == null ? null : new Rect(mSourceBounds); } /** * @return Extras to be added to the Intent sent to the Contextual Search app. These will be * merged with any other extras added to the Intent by ContextualSearchManagerService. */ @NonNull public Bundle getIntentExtras() { return new Bundle(mIntentExtras); } @Override public String toString() { return "ContextualSearchConfig{" + "mDisplayId=" + mDisplayId + ", " + "mSourceBounds=" + mSourceBounds + ", " + "mIntentExtras=" + mIntentExtras + '}'; } /** * Builder to create a {@link ContextualSearchConfig}. */ public static final class Builder { private int mDisplayId; @Nullable private Rect mSourceBounds; @NonNull private final Bundle mIntentExtras; /** * Creates a new Builder with default values. */ public Builder() { mDisplayId = Display.INVALID_DISPLAY; mSourceBounds = null; mIntentExtras = new Bundle(); } /** * Creates a new builder and initializes it with the values from the given * {@link ContextualSearchConfig}. * * @param config The config to copy values from. */ public Builder(@NonNull ContextualSearchConfig config) { mDisplayId = config.getDisplayId(); mSourceBounds = config.getSourceBounds(); mIntentExtras = config.getIntentExtras(); } /** * Sets the display ID for the contextual search invocation. * * @param displayId The ID of the display where the search was triggered. This determines * where the screenshot is taken and displayed for user interaction. If the * display ID is invalid, the invocation will fail silently. If not * specified, the system will use {@link Display#DEFAULT_DISPLAY}, or the * Activity's display if launched from an Activity. * @return This Builder object to allow for chaining of calls. */ @NonNull public Builder setDisplayId(int displayId) { mDisplayId = displayId; return this; } /** * Sets the source bounds for the contextual search invocation. * * @param sourceBounds The bounds of the source element that triggered the search, in screen * coordinates. Can be null if not available. * @return This Builder object to allow for chaining of calls. */ @NonNull public Builder setSourceBounds(@Nullable Rect sourceBounds) { mSourceBounds = sourceBounds == null ? null : new Rect(sourceBounds); return this; } /** * Sets any additional extras to be added to the intent sent to the Contextual Search app. * * @param intentExtras This will be merged with any other extras added to the intent by * ContextualSearchManagerService. To avoid having your extras * overwritten, prefix the keys with an agreed package name. * @return This Builder object to allow for chaining of calls. */ @NonNull public Builder setIntentExtras(@Nullable Bundle intentExtras) { mIntentExtras.clear(); if (intentExtras != null) { mIntentExtras.putAll(intentExtras); } return this; } /** * Builds the {@link ContextualSearchConfig} instance. * * @return The built {@link ContextualSearchConfig} object. */ @NonNull public ContextualSearchConfig build() { return new ContextualSearchConfig(this); } } }
core/java/android/app/contextualsearch/ContextualSearchManager.java +77 −22 Original line number Diff line number Diff line Loading @@ -20,8 +20,11 @@ import static android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.Activity; import android.app.contextualsearch.flags.Flags; import android.content.Context; import android.os.IBinder; Loading @@ -29,19 +32,20 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.util.Log; import android.view.Display; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.Set; /** * {@link ContextualSearchManager} is a system service to facilitate contextual search experience on * configured Android devices. * <p> * This class lets a caller start contextual search by calling {@link #startContextualSearch} * method. * configured Android devices. This involves capturing screenshots that the Contextual Search system * app presents to the user for interaction, such as selecting content on the screenshot to get a * search result or take an action such as calling a phone number or translating text. * * @hide */ Loading Loading @@ -256,16 +260,18 @@ public final class ContextualSearchManager { } /** * Used to check whether contextual search is available on the device. This method should be * called before calling {@link #startContextualSearch()} or adding any UI related to it to * ensure that the device is configured to support contextual search. * Used to check whether contextual search is available on the device. If this method returns * {code false}, you should not add any UI related to this feature, nor call * {@link #startContextualSearch(Activity, ContextualSearchConfig)}. It's rare but possible that * the return value of this method will change in subsequent calls, e.g. if the Contextual * Search app is disabled or enabled by the user. * * @see #startContextualSearch() * @return true if contextual search is available on the device, false otherwise. * @see #startContextualSearch(Activity, ContextualSearchConfig) * @return {@code true} if contextual search is currently available, {@code false} otherwise * * @hide */ @FlaggedApi(Flags.FLAG_SELF_INVOCATION) @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public boolean isContextualSearchAvailable() { if (DEBUG) Log.d(TAG, "isContextualSearchAvailable"); Loading Loading @@ -295,20 +301,60 @@ public final class ContextualSearchManager { * <p>This method will fail silently if Contextual Search is not available on the device. * * @param entrypoint the invocation entrypoint * @throws SecurityException if the caller does not have the {@link ACCESS_CONTEXTUAL_SEARCH} * permission. * * @hide */ @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH) @SystemApi public void startContextualSearch(@Entrypoint int entrypoint) { if (DEBUG) Log.d(TAG, "startContextualSearch; entrypoint: " + entrypoint); startContextualSearchInternal(entrypoint, null); } /** * Used to start contextual search for a given system entrypoint. * <p> * When {@link #startContextualSearch} is called, the system server does the following: * <ul> * <li>Resolves the activity using the package name and intent filter. The package name * is fetched from the config specified in ContextualSearchManagerService. * The activity must have ACTION_LAUNCH_CONTEXTUAL_SEARCH specified in its manifest. * <li>Puts the required extras in the launch intent, which may include a * {@link android.media.projection.MediaProjection} session. * <li>Launches the activity. * </ul> * </p> * * <p>This method will fail silently if Contextual Search is not available on the device. * * @param entrypoint the invocation entrypoint * @param config the invocation configuration parameters. If {@code null}, default configuration * will be applied, including launching on {@link Display#DEFAULT_DISPLAY}. * * @hide */ @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH) @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public void startContextualSearch(@Entrypoint int entrypoint, @Nullable ContextualSearchConfig config) { startContextualSearchInternal(entrypoint, config); } /** * Internal method to start contextual search with an entrypoint and optional config. */ @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH) private void startContextualSearchInternal(@Entrypoint int entrypoint, @Nullable ContextualSearchConfig config) { if (!VALID_ENTRYPOINT_VALUES.contains(entrypoint)) { throw new IllegalArgumentException("Invalid entrypoint: " + entrypoint); } if (DEBUG) Log.d(TAG, "startContextualSearch for entrypoint: " + entrypoint); if (DEBUG) { Log.d(TAG, "startContextualSearch; entrypoint: " + entrypoint + "; config: " + config); } try { mService.startContextualSearch(entrypoint); mService.startContextualSearch(entrypoint, config); } catch (RemoteException e) { if (DEBUG) Log.d(TAG, "Failed to startContextualSearch", e); e.rethrowFromSystemServer(); Loading @@ -319,27 +365,36 @@ public final class ContextualSearchManager { * Used to start Contextual Search from within an app. This will send a screenshot to the * Contextual Search app designated by the device manufacturer. The user can then select content * on the screenshot to get a search result or take an action such as calling a phone number or * translating the text. * translating the text. Note that the screenshot will capture the full display and may include * content outside of your Activity, e.g. in split screen mode. * * <p>Prior to calling this method or showing any UI related to it, you should verify that * Contextual Search is available on the device by using {@link #isContextualSearchAvailable()}. * Otherwise, this method will fail silently. * * <p>This method should only be called from an app that has a foreground Activity. * <p>Note: The system will use the display ID of your activity unless a displayId is specified * in the config. This is strongly discouraged unless you have a specific reason to specify a * different display. * * @see #isContextualSearchAvailable() * @throws SecurityException if the caller does not have a foreground Activity. * @param activity your foreground Activity from which the search is started * @param config the invocation configuration parameters. If {@code null}, default configuration * will be applied, including launching the search on the same display as your * activity. * @throws SecurityException if the caller does not have a foreground Activity * * @hide */ @FlaggedApi(Flags.FLAG_SELF_INVOCATION) @FlaggedApi(Flags.FLAG_CONFIG_PARAMETERS) @SystemApi public void startContextualSearch() { if (DEBUG) Log.d(TAG, "startContextualSearch from app"); public void startContextualSearch(@NonNull Activity activity, @Nullable ContextualSearchConfig config) { Objects.requireNonNull(activity); if (DEBUG) Log.d(TAG, "startContextualSearchForActivity(" + activity + ", " + config + ")"); try { mService.startContextualSearchForForegroundApp(); mService.startContextualSearchForActivity(activity.getActivityToken(), config); } catch (RemoteException e) { if (DEBUG) Log.d(TAG, "Failed to startContextualSearch", e); if (DEBUG) Log.d(TAG, "Failed to startContextualSearchForActivity", e); e.rethrowFromSystemServer(); } } Loading
core/java/android/app/contextualsearch/IContextualSearchManager.aidl +5 −2 Original line number Diff line number Diff line package android.app.contextualsearch; import android.app.contextualsearch.IContextualSearchCallback; parcelable ContextualSearchConfig; /** * @hide */ interface IContextualSearchManager { boolean isContextualSearchAvailable(); void startContextualSearchForForegroundApp(); oneway void startContextualSearch(int entrypoint); void startContextualSearchForActivity(in IBinder activityToken, in ContextualSearchConfig config); oneway void startContextualSearch(int entrypoint, in ContextualSearchConfig config); oneway void getContextualSearchState(in IBinder token, in IContextualSearchCallback callback); }
core/java/android/app/contextualsearch/flags.aconfig +17 −14 Original line number Diff line number Diff line Loading @@ -51,9 +51,12 @@ flag { } flag { name: "self_invocation" name: "config_parameters" namespace: "sysui_integrations" description: "Enable apps to self-invoke Contextual Search." bug: "368653769" description: "Allow invocation parameters to be passed to Contextual Search, including from apps." bug: "371552433" is_exported: true metadata { purpose: PURPOSE_BUGFIX } }