• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.settings.search;
16 
17 import static com.android.settings.slices.SliceDeepLinkSpringBoard.INTENT;
18 import static com.android.settings.slices.SliceDeepLinkSpringBoard.SETTINGS;
19 
20 import android.app.job.JobInfo;
21 import android.app.job.JobScheduler;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ServiceInfo;
26 import android.net.Uri;
27 import android.os.Binder;
28 import android.os.Build;
29 import android.provider.Settings;
30 import android.text.TextUtils;
31 import android.util.Log;
32 
33 import com.android.settings.R;
34 import com.android.settings.Utils;
35 import com.android.settings.slices.SettingsSliceProvider;
36 
37 import java.util.List;
38 import java.util.Locale;
39 
40 public interface DeviceIndexFeatureProvider {
41 
42     String TAG = "DeviceIndex";
43 
44     String INDEX_VERSION = "settings:index_version";
45     String INDEX_LANGUAGE = "settings:language";
46 
47     // Increment when new items are added to ensure they get pushed to the device index.
48     String VERSION = Build.FINGERPRINT;
49 
50     // When the device language changes, re-index so Slices trigger in device language.
51     Locale LANGUAGE = Locale.getDefault();
52 
isIndexingEnabled()53     boolean isIndexingEnabled();
54 
index(Context context, CharSequence title, Uri sliceUri, Uri launchUri, List<String> keywords)55     void index(Context context, CharSequence title, Uri sliceUri, Uri launchUri,
56             List<String> keywords);
57 
clearIndex(Context context)58     void clearIndex(Context context);
59 
updateIndex(Context context, boolean force)60     default void updateIndex(Context context, boolean force) {
61         if (!isIndexingEnabled()) {
62             Log.i(TAG, "Skipping: device index is not enabled");
63             return;
64         }
65 
66         if (!Utils.isDeviceProvisioned(context)) {
67             Log.w(TAG, "Skipping: device is not provisioned");
68             return;
69         }
70 
71         final ComponentName jobComponent = new ComponentName(context.getPackageName(),
72                 DeviceIndexUpdateJobService.class.getName());
73 
74         try {
75             final int callerUid = Binder.getCallingUid();
76             final ServiceInfo si = context.getPackageManager().getServiceInfo(jobComponent,
77                     PackageManager.MATCH_DIRECT_BOOT_AWARE
78                             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
79             if (si == null) {
80                 Log.w(TAG, "Skipping: No such service " + jobComponent);
81                 return;
82             }
83             if (si.applicationInfo.uid != callerUid) {
84                 Log.w(TAG, "Skipping: Uid cannot schedule DeviceIndexUpdate: " + callerUid);
85                 return;
86             }
87         } catch (PackageManager.NameNotFoundException e) {
88             Log.w(TAG, "Skipping: error finding DeviceIndexUpdateJobService from packageManager");
89             return;
90         }
91 
92         if (!force && skipIndex(context)) {
93             Log.i(TAG, "Skipping: already indexed.");
94             // No need to update.
95             return;
96         }
97 
98         // Prevent scheduling multiple jobs
99         setIndexState(context);
100 
101         final int jobId = context.getResources().getInteger(R.integer.device_index_update);
102         // Schedule a job so that we know it'll be able to complete, but try to run as
103         // soon as possible.
104         context.getSystemService(JobScheduler.class).schedule(
105                 new JobInfo.Builder(jobId, jobComponent)
106                         .setPersisted(true)
107                         .setMinimumLatency(1000)
108                         .setOverrideDeadline(1)
109                         .build());
110 
111     }
112 
createDeepLink(String s)113     static Uri createDeepLink(String s) {
114         return new Uri.Builder().scheme(SETTINGS)
115                 .authority(SettingsSliceProvider.SLICE_AUTHORITY)
116                 .appendQueryParameter(INTENT, s)
117                 .build();
118     }
119 
skipIndex(Context context)120     static boolean skipIndex(Context context) {
121         final boolean isSameVersion = TextUtils.equals(
122                 Settings.Secure.getString(context.getContentResolver(), INDEX_VERSION), VERSION);
123         final boolean isSameLanguage = TextUtils.equals(
124                 Settings.Secure.getString(context.getContentResolver(), INDEX_LANGUAGE),
125                 LANGUAGE.toString());
126         return isSameLanguage && isSameVersion;
127     }
128 
setIndexState(Context context)129     static void setIndexState(Context context) {
130         Settings.Secure.putString(context.getContentResolver(), INDEX_VERSION, VERSION);
131         Settings.Secure.putString(context.getContentResolver(), INDEX_LANGUAGE,
132                 LANGUAGE.toString());
133     }
134 }
135