1 /*
2  * Copyright (C) 2017 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.settings.intelligence.search.indexing;
18 
19 import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY;
20 import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI;
21 
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.net.Uri;
26 import android.text.TextUtils;
27 
28 /**
29  * Utility class for {@like DatabaseIndexingManager} to handle the mapping between Payloads
30  * and Preference controllers, and managing indexable classes.
31  */
32 public class DatabaseIndexingUtils {
33 
34     private static final String TAG = "DatabaseIndexingUtils";
35 
36     // frameworks/base/proto/src/metrics_constants.proto#DASHBOARD_SEARCH_RESULTS
37     // Have to hardcode value here because we can't depend on internal framework constants.
38     public static final int DASHBOARD_SEARCH_RESULTS = 34;
39 
40     /**
41      * Below are internal contract between Settings/SettingsIntelligence to launch a search result
42      * page.
43      */
44     public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment";
45     public static final String EXTRA_SOURCE_METRICS_CATEGORY = ":settings:source_metrics";
46     public static final String EXTRA_FRAGMENT_ARG_KEY = ":settings:fragment_args_key";
47     public static final String EXTRA_SHOW_FRAGMENT_TITLE = ":settings:show_fragment_title";
48     public static final String SEARCH_RESULT_TRAMPOLINE_ACTION =
49             "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
50 
51     // Additional extra of Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK.
52     // Set & get Uri of the Intent separately to prevent failure of Intent#ParseUri.
53     private static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA =
54             "settings_large_screen_deep_link_intent_data";
55 
56     /**
57      * Builds intent that launches the search destination as a sub-setting.
58      */
buildSearchTrampolineIntent(String className, String key, String screenTitle, String highlightMenuKey)59     public static Intent buildSearchTrampolineIntent(String className, String key,
60             String screenTitle, String highlightMenuKey) {
61         final Intent intent = new Intent(SEARCH_RESULT_TRAMPOLINE_ACTION);
62         intent.putExtra(EXTRA_SHOW_FRAGMENT, className)
63                 .putExtra(EXTRA_SHOW_FRAGMENT_TITLE, screenTitle)
64                 .putExtra(EXTRA_SOURCE_METRICS_CATEGORY, DASHBOARD_SEARCH_RESULTS)
65                 .putExtra(EXTRA_FRAGMENT_ARG_KEY, key)
66                 .putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, highlightMenuKey);
67         return intent;
68     }
69 
70     /**
71      *  Builds intent that launches the search destination as a deep link.
72      */
buildSearchTrampolineIntent(String action, String targetPackage, String targetClass, String key, String highlightMenuKey)73     public static Intent buildSearchTrampolineIntent(String action, String targetPackage,
74             String targetClass, String key, String highlightMenuKey) {
75         final Intent intent = new Intent(SEARCH_RESULT_TRAMPOLINE_ACTION);
76         intent.putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
77                         buildDirectSearchResultIntent(action, targetPackage, targetClass, key)
78                                 .toUri(Intent.URI_INTENT_SCHEME))
79                 .putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, highlightMenuKey);
80         return intent;
81     }
82 
83     /**
84      *  Builds intent that launches the search destination as a deep link.
85      */
buildSearchTrampolineIntent(Intent targetIntent, String highlightMenuKey)86     public static Intent buildSearchTrampolineIntent(Intent targetIntent, String highlightMenuKey) {
87         // Relay target intent data to prevent future failure of Intent#ParseUri.
88         final Uri data = targetIntent.getData();
89         targetIntent = new Intent(targetIntent);
90         targetIntent.setData(null);
91         final Intent intent = new Intent(SEARCH_RESULT_TRAMPOLINE_ACTION);
92         intent.putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
93                         targetIntent.toUri(Intent.URI_INTENT_SCHEME))
94                 .putExtra(EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY, highlightMenuKey)
95                 .putExtra(EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_DATA, data);
96         return intent;
97     }
98 
buildDirectSearchResultIntent(String action, String targetPackage, String targetClass, String key)99     public static Intent buildDirectSearchResultIntent(String action, String targetPackage,
100             String targetClass, String key) {
101         final Intent intent = new Intent(action).putExtra(EXTRA_FRAGMENT_ARG_KEY, key);
102         if (!TextUtils.isEmpty(targetPackage) && !TextUtils.isEmpty(targetClass)) {
103             final ComponentName component = new ComponentName(targetPackage, targetClass);
104             intent.setComponent(component);
105         }
106         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
107         return intent;
108     }
109 
110     // TODO REFACTOR (b/62807132) Add inline support with proper intents.
111 //    /**
112 //     * @param className which wil provide the map between from {@link Uri}s to
113 //     *                  {@link PreferenceControllerMixin}
114 //     * @return A map between {@link Uri}s and {@link PreferenceControllerMixin}s to get the
115 // payload
116 //     * types for Settings.
117 //     */
118 //    public static Map<String, PreferenceControllerMixin> getPreferenceControllerUriMap(
119 //            String className, Context context) {
120 //        if (context == null) {
121 //            return null;
122 //        }
123 //
124 //        final Class<?> clazz = getIndexableClass(className);
125 //
126 //        if (clazz == null) {
127 //            Log.d(TAG, "SearchIndexableResource '" + className +
128 //                    "' should implement the " + Indexable.class.getName() + " interface!");
129 //            return null;
130 //        }
131 //
132 //        // Will be non null only for a Local provider implementing a
133 //        // SEARCH_INDEX_DATA_PROVIDER field
134 //        final Indexable.SearchIndexProvider provider = getSearchIndexProvider(clazz);
135 //
136 //        List<AbstractPreferenceController> controllers =
137 //                provider.getPreferenceControllers(context);
138 //
139 //        if (controllers == null) {
140 //            return null;
141 //        }
142 //
143 //        ArrayMap<String, PreferenceControllerMixin> map = new ArrayMap<>();
144 //
145 //        for (AbstractPreferenceController controller : controllers) {
146 //            if (controller instanceof PreferenceControllerMixin) {
147 //                map.put(controller.getPreferenceKey(), (PreferenceControllerMixin) controller);
148 //            } else {
149 //                throw new IllegalStateException(controller.getClass().getName()
150 //                        + " must implement " + PreferenceControllerMixin.class.getName());
151 //            }
152 //        }
153 //
154 //        return map;
155 //    }
156 //
157 //    /**
158 //     * @param uriMap Map between the {@link PreferenceControllerMixin} keys
159 //     *               and the controllers themselves.
160 //     * @param key    The look-up key
161 //     * @return The Payload from the {@link PreferenceControllerMixin} specified by the key,
162 //     * if it exists. Otherwise null.
163 //     */
164 //    public static ResultPayload getPayloadFromUriMap(Map<String, PreferenceControllerMixin>
165 // uriMap,
166 //            String key) {
167 //        if (uriMap == null) {
168 //            return null;
169 //        }
170 //
171 //        PreferenceControllerMixin controller = uriMap.get(key);
172 //        if (controller == null) {
173 //            return null;
174 //        }
175 //
176 //        return controller.getResultPayload();
177 //    }
178 
179 }
180