1 /*
2  * Copyright (C) 2020 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.server.location.gnss;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.database.ContentObserver;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.UserHandle;
25 import android.provider.Settings;
26 import android.util.Log;
27 
28 import com.android.internal.annotations.VisibleForTesting;
29 
30 import java.util.ArrayList;
31 import java.util.List;
32 
33 /**
34  * Detects blacklist change and updates the blacklist.
35  */
36 class GnssSatelliteBlacklistHelper {
37 
38     private static final String TAG = "GnssBlacklistHelper";
39     private static final String BLACKLIST_DELIMITER = ",";
40 
41     private final Context mContext;
42     private final GnssSatelliteBlacklistCallback mCallback;
43 
44     interface GnssSatelliteBlacklistCallback {
onUpdateSatelliteBlacklist(int[] constellations, int[] svids)45         void onUpdateSatelliteBlacklist(int[] constellations, int[] svids);
46     }
47 
GnssSatelliteBlacklistHelper(Context context, Looper looper, GnssSatelliteBlacklistCallback callback)48     GnssSatelliteBlacklistHelper(Context context, Looper looper,
49             GnssSatelliteBlacklistCallback callback) {
50         mContext = context;
51         mCallback = callback;
52         ContentObserver contentObserver = new ContentObserver(new Handler(looper)) {
53             @Override
54             public void onChange(boolean selfChange) {
55                 updateSatelliteBlacklist();
56             }
57         };
58         mContext.getContentResolver().registerContentObserver(
59                 Settings.Global.getUriFor(
60                         Settings.Global.GNSS_SATELLITE_BLACKLIST),
61                 true,
62                 contentObserver, UserHandle.USER_ALL);
63     }
64 
updateSatelliteBlacklist()65     void updateSatelliteBlacklist() {
66         ContentResolver resolver = mContext.getContentResolver();
67         String blacklist = Settings.Global.getString(
68                 resolver,
69                 Settings.Global.GNSS_SATELLITE_BLACKLIST);
70         if (blacklist == null) {
71             blacklist = "";
72         }
73         Log.i(TAG, String.format("Update GNSS satellite blacklist: %s", blacklist));
74 
75         List<Integer> blacklistValues;
76         try {
77             blacklistValues = parseSatelliteBlacklist(blacklist);
78         } catch (NumberFormatException e) {
79             Log.e(TAG, "Exception thrown when parsing blacklist string.", e);
80             return;
81         }
82 
83         if (blacklistValues.size() % 2 != 0) {
84             Log.e(TAG, "blacklist string has odd number of values."
85                     + "Aborting updateSatelliteBlacklist");
86             return;
87         }
88 
89         int length = blacklistValues.size() / 2;
90         int[] constellations = new int[length];
91         int[] svids = new int[length];
92         for (int i = 0; i < length; i++) {
93             constellations[i] = blacklistValues.get(i * 2);
94             svids[i] = blacklistValues.get(i * 2 + 1);
95         }
96         mCallback.onUpdateSatelliteBlacklist(constellations, svids);
97     }
98 
99     @VisibleForTesting
parseSatelliteBlacklist(String blacklist)100     static List<Integer> parseSatelliteBlacklist(String blacklist) throws NumberFormatException {
101         String[] strings = blacklist.split(BLACKLIST_DELIMITER);
102         List<Integer> parsed = new ArrayList<>(strings.length);
103         for (String string : strings) {
104             string = string.trim();
105             if (!"".equals(string)) {
106                 int value = Integer.parseInt(string);
107                 if (value < 0) {
108                     throw new NumberFormatException("Negative value is invalid.");
109                 }
110                 parsed.add(value);
111             }
112         }
113         return parsed;
114     }
115 }
116