• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 com.android.app.search;
18 
19 import static com.android.app.search.LayoutType.TALL_CARD_WITH_IMAGE_NO_ICON;
20 
21 import android.app.blob.BlobHandle;
22 import android.app.search.SearchAction;
23 import android.app.search.SearchTarget;
24 import android.os.Bundle;
25 import android.text.TextUtils;
26 
27 import androidx.annotation.Nullable;
28 
29 /**
30  * Helper class that defines key string value for {@link SearchTarget#getExtras()}
31  * and also defines helper methods
32  */
33 public class SearchTargetExtras {
34 
35     /** on device data related extras and helper methods */
36     // Used to extra component name.
37     public static final String BUNDLE_EXTRA_CLASS = "class";
38 
39     // Used for UI treatment. Labels whether search target should support quick launch.
40     public static final String BUNDLE_EXTRA_QUICK_LAUNCH = "quick_launch";
41     // Used for UI treatment. Targets grouped with same group id are decorated together.
42     public static final String BUNDLE_EXTRA_GROUP_ID = "group_id";
43     public static final String BUNDLE_EXTRA_GROUP_DECORATE_TOGETHER = "decorate_together";
44     // Used if slice title should be rendered else where outside of slice (e.g., edit text).
45     public static final String BUNDLE_EXTRA_SLICE_TITLE = "slice_title";
46     // Used if slice view should be rendered using full height mode.
47     public static final String BUNDLE_EXTRA_USE_FULL_HEIGHT = "use_full_height";
48     public static final String BUNDLE_EXTRA_IS_NON_TAPPABLE = "is_non_tappable";
49     public static final String BUNDLE_EXTRA_TITLE_OVERWRITE = "title_overwrite";
50     // Used if subtitle view should be overridden to string that is not natively defined by the
51     // search target.
52     public static final String BUNDLE_EXTRA_SUBTITLE_OVERRIDE = "subtitle_override";
53 
54     // Used for logging. Returns whether spelling correction was applied.
55     public static final String BUNDLE_EXTRA_IS_QUERY_CORRECTED = "is_query_corrected";
56     // Used for logging. Returns whether the result matched block title or the inline item.
57     public static final String BUNDLE_EXTRA_RESULT_MATCH_USER_TYPED = "result_match_user_typed";
58     // Used for logging. Returns the timestamp when system service received the data.
59     public static final String BUNDLE_EXTRA_START_TIMESTAMP = "start_timestamp";
60     // Indicates the search result app location column.
61     public static final String BUNDLE_EXTRA_RESULT_APP_GRIDX = "app_gridx";
62 
63     // Used for thumbnail loading. Contains handle to retrieve Blobstore asset.
64     public static final String BUNDLE_EXTRA_BLOBSTORE_HANDLE = "blobstore_handle_key";
65 
66     // Used to denote this searchTarget is for recent block in 0-state.
67     public static final String EXTRAS_RECENT_BLOCK_TARGET = "recent_block_target";
68 
69     public static final int GROUPING = 1 << 1;
70 
71     @Nullable
getDecoratorId(@ullable SearchTarget target)72     public static String getDecoratorId(@Nullable SearchTarget target) {
73         return isTargetOrExtrasNull(target) ? null :
74                 target.getExtras().getString(BUNDLE_EXTRA_GROUP_ID);
75     }
76 
getDecoratorType(@ullable SearchTarget target)77     public static int getDecoratorType(@Nullable SearchTarget target) {
78         int type = 0;
79         if (isTargetOrExtrasNull(target)) {
80             return type;
81         }
82         if (!TextUtils.isEmpty(target.getExtras().getString(BUNDLE_EXTRA_GROUP_ID))) {
83             type |= GROUPING;
84         }
85         return type;
86     }
87 
88     /** Whether or not the SearchTarget's Extras contains a blobstore image. */
isSearchTargetBlobstoreAsset(@ullable SearchTarget target)89     public static boolean isSearchTargetBlobstoreAsset(@Nullable SearchTarget target) {
90         if (isTargetOrExtrasNull(target)) {
91             return false;
92         }
93         return target.getExtras().getParcelable(
94                 BUNDLE_EXTRA_BLOBSTORE_HANDLE) instanceof BlobHandle;
95     }
96 
97     /** Check if SearchTarget contains information to tell if this target is from recent block. */
isSearchTargetRecentItem(@ullable SearchTarget target)98     public static boolean isSearchTargetRecentItem(@Nullable SearchTarget target) {
99         if (isTargetOrExtrasNull(target)) {
100             return false;
101         }
102         return target.getExtras().getBoolean(EXTRAS_RECENT_BLOCK_TARGET, false);
103     }
104 
isTargetOrExtrasNull(@ullable SearchTarget target)105     private static boolean isTargetOrExtrasNull(@Nullable SearchTarget target) {
106         return target == null || target.getExtras() == null;
107     }
108 
109     /** Web data related extras and helper methods */
110     public static final String BUNDLE_EXTRA_PROXY_WEB_ITEM = "proxy_web_item";
111     public static final String BUNDLE_EXTRA_ENTITY = "is_entity";
112     public static final String BUNDLE_EXTRA_ANSWER = "is_answer";
113     public static final String BUNDLE_EXTRA_RESPONSE_ID = "response_id";
114     public static final String BUNDLE_EXTRA_LEARN_MORE_URL = "learn_more_url";
115     public static final String BUNDLE_EXTRA_PERSONAL = "is_personal";
116     public static final String BUNDLE_EXTRA_SUGGESTION_TYPE = "suggestion_type";
117     public static final String BUNDLE_EXTRA_SUGGEST_RENDER_TEXT = "suggest_render_text";
118     public static final String BUNDLE_EXTRA_ZERO_STATE_CACHE = "zero_state_cache";
119     public static final String BUNDLE_EXTRA_TALL_CARD_HEADER = "tall_card_header";
120     public static final String BUNDLE_EXTRA_TALL_CARD_IMAGE_DESCRIPTION =
121             "tall_card_image_description";
122     public static final String BUNDLE_EXTRA_BITMAP_URL = "bitmap_url";
123 
124     // Used for web suggestions count for both AA+ and QSB entry point.
125     // Returns the number of web suggestions to be shown.
126     public static final String WEB_SUG_COUNT = "web_sug_count";
127 
128     /**
129      *  Replaced with thumbnail crop type
130      *
131      *  Flag to control whether thumbnail(s) should fill the thumbnail container's width or not.
132      *  When this flag is true, when there are less than the maximum number of thumbnails in the
133      *  container, the thumbnails will stretch to fill the container's width.
134      *  When this flag is false, thumbnails will always be cropped to a square ratio even if
135      *  there aren't enough thumbnails to fill the container.
136      *
137      *  Only relevant in {@link LayoutType#THUMBNAIL_CONTAINER} and {@link LayoutType#THUMBNAIL}.
138      */
139     @Deprecated
140     public static final String BUNDLE_EXTRA_SHOULD_FILL_CONTAINER_WIDTH =
141             "should_fill_container_width";
142 
143     /**
144      * Flag to control thumbnail container's crop mode, controlling the layout
145      *
146      * <ul>
147      *     <li>SQUARE: Thumbnail(s) will be cropped to a square aspect ratio around the center.</li>
148      *     <li>FILL_WIDTH: Thumbnail(s) should collectively fill the thumbnail container's width.
149      *     When there are less than the maximum number of thumbnails in the container, the
150      *     layouts' width will stretch to fit the container, the images will fill the width
151      *     and then the top/bottom cropped to fit.</li>
152      *     <li>FILL_HEIGHT: Thumbnail(s) should fill height and be cropped to fit in the width
153      *     based on {@link BUNDLE_EXTRA_THUMBNAIL_MAX_COUNT} as the column count. When the image
154      *     width is larger than the width / column, both sides will be cropped while maintaining
155      *     the center.
156      *     When there are less thumbnails than the max count, the layout will be constrained to
157      *     equally divide the width of the container. If there are more thumbnails than the max
158      *     count, the excessive thumbnails will be ignored.</li>
159      * </ul>
160      *
161      * Only relevant in {@link LayoutType#THUMBNAIL_CONTAINER} and {@link LayoutType#THUMBNAIL}.
162      */
163     public static final String BUNDLE_EXTRA_THUMBNAIL_CROP_TYPE = "thumbnail_crop_type";
164     public enum ThumbnailCropType {
165         DEFAULT(0), // defaults to SQUARE behavior by {@link LayoutType#THUMBNAIL_CONTAINER}.
166         SQUARE(1),
167         FILL_WIDTH(2),
168         FILL_HEIGHT(3);
169 
170         private final int mTypeId;
171 
ThumbnailCropType(int typeId)172         ThumbnailCropType(int typeId) {
173             mTypeId = typeId;
174         }
175 
toTypeId()176         public int toTypeId() {
177             return mTypeId;
178         }
179     };
180 
181     /**
182      * How many grid spaces for the thumbnail container should be reserved.
183      * Only relevant for {@link ThumbnailCropType#FILL_HEIGHT} crop type.
184      */
185     public static final String BUNDLE_EXTRA_THUMBNAIL_MAX_COUNT = "thumbnail_max_count";
186 
187     /**
188      *  Flag to control whether the SearchTarget's label should be hidden.
189      *  When this flag is true, label will be hidden.
190      *  When this flag is false (or omitted), {@link SearchAction#mTitle} will be shown.
191      */
192     public static final String BUNDLE_EXTRA_HIDE_LABEL =
193             "hide_label";
194     public static final String BUNDLE_EXTRA_SUGGESTION_ACTION_TEXT = "suggestion_action_text";
195     public static final String BUNDLE_EXTRA_SUGGESTION_ACTION_RPC = "suggestion_action_rpc";
196     public static final String BUNDLE_EXTRA_SUPPORT_QUERY_BUILDER = "support_query_builder";
197     public static final String BUNDLE_EXTRA_SUGGEST_RAW_TEXT = "suggest_raw_text";
198     public static final String BUNDLE_EXTRA_SUGGEST_TRUNCATE_START = "suggest_truncate_start";
199 
200     /** Web data related helper methods */
isEntity(@ullable SearchTarget target)201     public static boolean isEntity(@Nullable SearchTarget target) {
202         return target != null && target.getExtras() != null
203                 && target.getExtras().getBoolean(BUNDLE_EXTRA_ENTITY);
204     }
205 
isAnswer(@ullable SearchTarget target)206     public static boolean isAnswer(@Nullable SearchTarget target) {
207         return target != null && target.getExtras() != null
208                 && target.getExtras().getBoolean(BUNDLE_EXTRA_ANSWER);
209     }
210 
211     /** Whether the search target is a rich answer web result. */
isRichAnswer(@ullable SearchTarget target)212     public static boolean isRichAnswer(@Nullable SearchTarget target) {
213         return target != null && isAnswer(target)
214                 && target.getLayoutType().equals(TALL_CARD_WITH_IMAGE_NO_ICON);
215     }
216 
217     /** Get the crop type thumbnails should use. Returns DEFAULT if not specified. */
getThumbnailCropType(@ullable SearchTarget target)218     public static ThumbnailCropType getThumbnailCropType(@Nullable SearchTarget target)
219             throws ArrayIndexOutOfBoundsException {
220         Bundle extras = target == null ? Bundle.EMPTY : target.getExtras();
221         if (extras.isEmpty()) {
222             return ThumbnailCropType.DEFAULT;
223         }
224         ThumbnailCropType cropType = ThumbnailCropType.values()[extras.getInt(
225                 BUNDLE_EXTRA_THUMBNAIL_CROP_TYPE)];
226         return cropType != null ? cropType : ThumbnailCropType.DEFAULT;
227     }
228 }
229