1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.app.contextualsearch;
18 
19 import static android.Manifest.permission.ACCESS_CONTEXTUAL_SEARCH;
20 
21 import android.annotation.FlaggedApi;
22 import android.annotation.IntDef;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SystemApi;
25 import android.app.contextualsearch.flags.Flags;
26 import android.content.Context;
27 import android.os.IBinder;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.os.SystemClock;
31 import android.util.Log;
32 
33 import java.lang.annotation.Retention;
34 import java.lang.annotation.RetentionPolicy;
35 
36 /**
37  * {@link ContextualSearchManager} is a system service to facilitate contextual search experience on
38  * configured Android devices.
39  * <p>
40  * This class lets a caller start contextual search by calling {@link #startContextualSearch}
41  * method.
42  *
43  * @hide
44  */
45 @SystemApi
46 @FlaggedApi(Flags.FLAG_ENABLE_SERVICE)
47 public final class ContextualSearchManager {
48 
49     /**
50      * Key to get the entrypoint from the extras of the activity launched by contextual search.
51      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
52      */
53     public static final String EXTRA_ENTRYPOINT =
54             "android.app.contextualsearch.extra.ENTRYPOINT";
55 
56     /**
57      * Key to get the flag_secure value from the extras of the activity launched by contextual
58      * search. The value will be true if flag_secure is found in any of the visible activities.
59      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
60      */
61     public static final String EXTRA_FLAG_SECURE_FOUND =
62             "android.app.contextualsearch.extra.FLAG_SECURE_FOUND";
63 
64     /**
65      * Key to get the screenshot from the extras of the activity launched by contextual search.
66      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
67      */
68     public static final String EXTRA_SCREENSHOT =
69             "android.app.contextualsearch.extra.SCREENSHOT";
70 
71     /**
72      * Key to check whether managed profile is visible from the extras of the activity launched by
73      * contextual search. The value will be true if any one of the visible apps is managed.
74      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
75      */
76     public static final String EXTRA_IS_MANAGED_PROFILE_VISIBLE =
77             "android.app.contextualsearch.extra.IS_MANAGED_PROFILE_VISIBLE";
78 
79     /**
80      * Key to get the list of visible packages from the extras of the activity launched by
81      * contextual search.
82      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
83      */
84     public static final String EXTRA_VISIBLE_PACKAGE_NAMES =
85             "android.app.contextualsearch.extra.VISIBLE_PACKAGE_NAMES";
86 
87     /**
88      * Key to get the time the user made the invocation request, based on
89      * {@link SystemClock#uptimeMillis()}.
90      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
91      *
92      * TODO: un-hide in W
93      *
94      * @hide
95      */
96     public static final String EXTRA_INVOCATION_TIME_MS =
97             "android.app.contextualsearch.extra.INVOCATION_TIME_MS";
98 
99     /**
100      * Key to get the binder token from the extras of the activity launched by contextual search.
101      * This token is needed to invoke {@link CallbackToken#getContextualSearchState} method.
102      * Only supposed to be used with ACTON_LAUNCH_CONTEXTUAL_SEARCH.
103      */
104     public static final String EXTRA_TOKEN = "android.app.contextualsearch.extra.TOKEN";
105     /**
106      * Intent action for contextual search invocation. The app providing the contextual search
107      * experience must add this intent filter action to the activity it wants to be launched.
108      * <br>
109      * <b>Note</b> This activity must not be exported.
110      */
111     public static final String ACTION_LAUNCH_CONTEXTUAL_SEARCH =
112             "android.app.contextualsearch.action.LAUNCH_CONTEXTUAL_SEARCH";
113 
114     /** Entrypoint to be used when a user long presses on the nav handle. */
115     public static final int ENTRYPOINT_LONG_PRESS_NAV_HANDLE = 1;
116     /** Entrypoint to be used when a user long presses on the home button. */
117     public static final int ENTRYPOINT_LONG_PRESS_HOME = 2;
118     /** Entrypoint to be used when a user long presses on the overview button. */
119     public static final int ENTRYPOINT_LONG_PRESS_OVERVIEW = 3;
120     /** Entrypoint to be used when a user presses the action button in overview. */
121     public static final int ENTRYPOINT_OVERVIEW_ACTION = 4;
122     /** Entrypoint to be used when a user presses the context menu button in overview. */
123     public static final int ENTRYPOINT_OVERVIEW_MENU = 5;
124     /** Entrypoint to be used by system actions like TalkBack, Accessibility etc. */
125     public static final int ENTRYPOINT_SYSTEM_ACTION = 9;
126     /** Entrypoint to be used when a user long presses on the meta key. */
127     public static final int ENTRYPOINT_LONG_PRESS_META = 10;
128     /**
129      * The {@link Entrypoint} annotation is used to standardize the entrypoints supported by
130      * {@link #startContextualSearch} method.
131      *
132      * @hide
133      */
134     @IntDef(prefix = {"ENTRYPOINT_"}, value = {
135             ENTRYPOINT_LONG_PRESS_NAV_HANDLE,
136             ENTRYPOINT_LONG_PRESS_HOME,
137             ENTRYPOINT_LONG_PRESS_OVERVIEW,
138             ENTRYPOINT_OVERVIEW_ACTION,
139             ENTRYPOINT_OVERVIEW_MENU,
140             ENTRYPOINT_SYSTEM_ACTION,
141             ENTRYPOINT_LONG_PRESS_META
142     })
143     @Retention(RetentionPolicy.SOURCE)
144     public @interface Entrypoint {
145     }
146     private static final String TAG = ContextualSearchManager.class.getSimpleName();
147     private static final boolean DEBUG = false;
148 
149     private final IContextualSearchManager mService;
150 
151     /** @hide */
ContextualSearchManager()152     public ContextualSearchManager() {
153         if (DEBUG) Log.d(TAG, "ContextualSearchManager created");
154         IBinder b = ServiceManager.getService(Context.CONTEXTUAL_SEARCH_SERVICE);
155         mService = IContextualSearchManager.Stub.asInterface(b);
156     }
157 
158     /**
159      * Used to start contextual search.
160      * <p>
161      *     When {@link #startContextualSearch} is called, the system server does the following:
162      *     <ul>
163      *         <li>Resolves the activity using the package name and intent filter. The package name
164      *             is fetched from the config specified in ContextualSearchManagerService.
165      *             The activity must have ACTION_LAUNCH_CONTEXTUAL_SEARCH specified in its manifest.
166      *         <li>Puts the required extras in the launch intent.
167      *         <li>Launches the activity.
168      *     </ul>
169      * </p>
170      *
171      * @param entrypoint the invocation entrypoint
172      */
173     @RequiresPermission(ACCESS_CONTEXTUAL_SEARCH)
startContextualSearch(@ntrypoint int entrypoint)174     public void startContextualSearch(@Entrypoint int entrypoint) {
175         if (DEBUG) Log.d(TAG, "startContextualSearch for entrypoint: " + entrypoint);
176         try {
177             mService.startContextualSearch(entrypoint);
178         } catch (RemoteException e) {
179             if (DEBUG) Log.d(TAG, "Failed to startContextualSearch", e);
180             e.rethrowFromSystemServer();
181         }
182     }
183 }
184