summaryrefslogtreecommitdiff
path: root/src/com/android/dialer/compat/FilteredNumberCompat.java
blob: 3ad45e87dbd165ad983e1fef15f93ce8dd8ac904 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License
 */

    package com.android.dialer.compat;

import com.google.common.base.Preconditions;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.telephony.PhoneNumberUtils;

import com.android.contacts.common.compat.CompatUtils;
import com.android.contacts.common.testing.NeededForTesting;
import com.android.dialer.DialerApplication;
import com.android.dialer.database.FilteredNumberContract.FilteredNumber;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberSources;
import com.android.dialer.database.FilteredNumberContract.FilteredNumberTypes;

import java.util.ArrayList;
import java.util.List;

/**
 * Compatibility class to encapsulate logic to switch between call blocking using
 * {@link com.android.dialer.database.FilteredNumberContract} and using
 * {@link android.provider.BlockedNumberContract}. This class should be used rather than explicitly
 * referencing columns from either contract class in situations where both blocking solutions may be
 * used.
 */
public class FilteredNumberCompat {

    protected static final String HAS_MIGRATED_TO_NEW_BLOCKING_KEY = "migratedToNewBlocking";

    // Flag to enable feature.
    // TODO(maxwelb) remove when ready to enable new filtering.
    private static final boolean isNewFilteringEnabled = false;

    private static Boolean isEnabledForTest;

    /**
     * @return The column name for ID in the filtered number database.
     */
    public static String getIdColumnName() {
        return useNewFiltering() ? BlockedNumbersSdkCompat._ID : FilteredNumberColumns._ID;
    }

    /**
     * @return The column name for type in the filtered number database. Will be {@code null} for
     * the framework blocking implementation.
     */
    @Nullable
    public static String getTypeColumnName() {
        return useNewFiltering() ? null : FilteredNumberColumns.TYPE;
    }

    /**
     * @return The column name for source in the filtered number database. Will be {@code null} for
     * the framework blocking implementation
     */
    @Nullable
    public static String getSourceColumnName() {
        return useNewFiltering() ? null : FilteredNumberColumns.SOURCE;
    }

    /**
     * @return The column name for the original number in the filtered number database.
     */
    public static String getOriginalNumberColumnName() {
        return useNewFiltering() ? BlockedNumbersSdkCompat.COLUMN_ORIGINAL_NUMBER
                : FilteredNumberColumns.NUMBER;
    }

    /**
     * @return The column name for country iso in the filtered number database. Will be {@code null}
     * the framework blocking implementation
     */
    @Nullable
    public static String getCountryIsoColumnName() {
        return useNewFiltering() ? null : FilteredNumberColumns.COUNTRY_ISO;
    }

    /**
     * @return The column name for the e164 formatted number in the filtered number database.
     */
    public static String getE164NumberColumnName() {
        return useNewFiltering() ? BlockedNumbersSdkCompat.E164_NUMBER
                : FilteredNumberColumns.NORMALIZED_NUMBER;
    }

    /**
     * @return {@code true} if the current SDK version supports using new filtering, {@code false}
     * otherwise.
     */
    public static boolean canUseNewFiltering() {
        if (isEnabledForTest != null) {
            return CompatUtils.isNCompatible() && isEnabledForTest;
        }
        return CompatUtils.isNCompatible() && isNewFilteringEnabled;
    }

    /**
     * @return {@code true} if the new filtering should be used, i.e. it's enabled and any necessary
     * migration has been performed, {@code false} otherwise.
     */
    public static boolean useNewFiltering() {
        return canUseNewFiltering() && hasMigratedToNewBlocking();
    }

    /**
     * @return {@code true} if the user has migrated to use
     * {@link android.provider.BlockedNumberContract} blocking, {@code false} otherwise.
     */
    public static boolean hasMigratedToNewBlocking() {
        return PreferenceManager.getDefaultSharedPreferences(DialerApplication.getContext())
                .getBoolean(HAS_MIGRATED_TO_NEW_BLOCKING_KEY, false);
    }

    /**
     * Called to inform this class whether the user has fully migrated to use
     * {@link android.provider.BlockedNumberContract} blocking or not.
     *
     * @param hasMigrated {@code true} if the user has migrated, {@code false} otherwise.
     */
    @NeededForTesting
    public static void setHasMigratedToNewBlocking(boolean hasMigrated) {
        PreferenceManager.getDefaultSharedPreferences(DialerApplication.getContext()).edit()
                .putBoolean(HAS_MIGRATED_TO_NEW_BLOCKING_KEY, hasMigrated).apply();
    }

    @NeededForTesting
    public static void setIsEnabledForTest(Boolean isEnabled) {
        isEnabledForTest = isEnabled;
    }

    /**
     * Gets the content {@link Uri} for number filtering.
     *
     * @param id The optional id to append with the base content uri.
     * @return The Uri for number filtering.
     */
    public static Uri getContentUri(@Nullable Integer id) {
        if (id == null) {
            return getBaseUri();
        }
        return ContentUris.withAppendedId(getBaseUri(), id);
    }


    private static Uri getBaseUri() {
        return useNewFiltering() ? BlockedNumbersSdkCompat.CONTENT_URI : FilteredNumber.CONTENT_URI;
    }

    /**
     * Removes any null column names from the given projection array. This method is intended to be
     * used to strip out any column names that aren't available in every version of number blocking.
     * Example:
     * {@literal
     *   getContext().getContentResolver().query(
     *       someUri,
     *       // Filtering ensures that no non-existant columns are queried
     *       FilteredNumberCompat.filter(new String[] {FilteredNumberCompat.getIdColumnName(),
     *           FilteredNumberCompat.getTypeColumnName()},
     *       FilteredNumberCompat.getE164NumberColumnName() + " = ?",
     *       new String[] {e164Number});
     * }
     *
     * @param projection The projection array.
     * @return The filtered projection array.
     */
    @Nullable
    public static String[] filter(@Nullable String[] projection) {
        if (projection == null) {
            return null;
        }
        List<String> filtered = new ArrayList<>();
        for (String column : projection) {
            if (column != null) {
                filtered.add(column);
            }
        }
        return filtered.toArray(new String[filtered.size()]);
    }

    /**
     * Creates a new {@link ContentValues} suitable for inserting in the filtered number table.
     *
     * @param number The unformatted number to insert.
     * @param e164Number (optional) The number to insert formatted to E164 standard.
     * @param countryIso (optional) The country iso to use to format the number.
     * @return The ContentValues to insert.
     * @throws NullPointerException If number is null.
     */
    public static ContentValues newBlockNumberContentValues(String number,
            @Nullable String e164Number, @Nullable String countryIso) {
        ContentValues contentValues = new ContentValues();
        contentValues.put(getOriginalNumberColumnName(), Preconditions.checkNotNull(number));
        if (!useNewFiltering()) {
            if (e164Number == null) {
                e164Number = PhoneNumberUtils.formatNumberToE164(number, countryIso);
            }
            contentValues.put(getE164NumberColumnName(), e164Number);
            contentValues.put(getCountryIsoColumnName(), countryIso);
            contentValues.put(getTypeColumnName(), FilteredNumberTypes.BLOCKED_NUMBER);
            contentValues.put(getSourceColumnName(), FilteredNumberSources.USER);
        }
        return contentValues;
    }
}