1 /*
2  * Copyright (C) 2015 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.dialer.blocking;
18 
19 import android.annotation.TargetApi;
20 import android.content.ContentResolver;
21 import android.content.ContentValues;
22 import android.content.Context;
23 import android.database.Cursor;
24 import android.os.AsyncTask;
25 import android.os.Build.VERSION_CODES;
26 import android.provider.BlockedNumberContract.BlockedNumbers;
27 import android.support.annotation.RequiresApi;
28 import com.android.dialer.common.LogUtil;
29 import com.android.dialer.database.FilteredNumberContract;
30 import com.android.dialer.database.FilteredNumberContract.FilteredNumber;
31 import com.android.dialer.database.FilteredNumberContract.FilteredNumberColumns;
32 import java.util.Objects;
33 
34 /**
35  * Class which should be used to migrate numbers from {@link FilteredNumberContract} blocking to
36  * {@link android.provider.BlockedNumberContract} blocking.
37  */
38 @TargetApi(VERSION_CODES.M)
39 public class BlockedNumbersMigrator {
40 
41   private final Context context;
42 
43   /**
44    * Creates a new BlockedNumbersMigrate, using the given {@link ContentResolver} to perform queries
45    * against the blocked numbers tables.
46    */
BlockedNumbersMigrator(Context context)47   public BlockedNumbersMigrator(Context context) {
48     this.context = Objects.requireNonNull(context);
49   }
50 
51   @RequiresApi(VERSION_CODES.N)
52   @TargetApi(VERSION_CODES.N)
migrateToNewBlockingInBackground(ContentResolver resolver)53   private static boolean migrateToNewBlockingInBackground(ContentResolver resolver) {
54     try (Cursor cursor =
55         resolver.query(
56             FilteredNumber.CONTENT_URI,
57             new String[] {FilteredNumberColumns.NUMBER},
58             null,
59             null,
60             null)) {
61       if (cursor == null) {
62         LogUtil.i(
63             "BlockedNumbersMigrator.migrateToNewBlockingInBackground", "migrate - cursor was null");
64         return false;
65       }
66 
67       LogUtil.i(
68           "BlockedNumbersMigrator.migrateToNewBlockingInBackground",
69           "migrate - attempting to migrate " + cursor.getCount() + "numbers");
70 
71       int numMigrated = 0;
72       while (cursor.moveToNext()) {
73         String originalNumber =
74             cursor.getString(cursor.getColumnIndex(FilteredNumberColumns.NUMBER));
75         if (isNumberInNewBlocking(resolver, originalNumber)) {
76           LogUtil.i(
77               "BlockedNumbersMigrator.migrateToNewBlockingInBackground",
78               "migrate - number was already blocked in new blocking");
79           continue;
80         }
81         ContentValues values = new ContentValues();
82         values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, originalNumber);
83         resolver.insert(BlockedNumbers.CONTENT_URI, values);
84         ++numMigrated;
85       }
86       LogUtil.i(
87           "BlockedNumbersMigrator.migrateToNewBlockingInBackground",
88           "migrate - migration complete. " + numMigrated + " numbers migrated.");
89       return true;
90     }
91   }
92 
93   @RequiresApi(VERSION_CODES.N)
94   @TargetApi(VERSION_CODES.N)
isNumberInNewBlocking(ContentResolver resolver, String originalNumber)95   private static boolean isNumberInNewBlocking(ContentResolver resolver, String originalNumber) {
96     try (Cursor cursor =
97         resolver.query(
98             BlockedNumbers.CONTENT_URI,
99             new String[] {BlockedNumbers.COLUMN_ID},
100             BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " = ?",
101             new String[] {originalNumber},
102             null)) {
103       return cursor != null && cursor.getCount() != 0;
104     }
105   }
106 
107   /**
108    * Copies all of the numbers in the {@link FilteredNumberContract} block list to the {@link
109    * android.provider.BlockedNumberContract} block list.
110    *
111    * @param listener {@link Listener} called once the migration is complete.
112    * @return {@code true} if the migrate can be attempted, {@code false} otherwise.
113    * @throws NullPointerException if listener is null
114    */
migrate(final Listener listener)115   public boolean migrate(final Listener listener) {
116     LogUtil.i("BlockedNumbersMigrator.migrate", "migrate - start");
117     if (!FilteredNumberCompat.canUseNewFiltering()) {
118       LogUtil.i("BlockedNumbersMigrator.migrate", "migrate - can't use new filtering");
119       return false;
120     }
121     Objects.requireNonNull(listener);
122     new MigratorTask(listener).execute();
123     return true;
124   }
125 
126   /**
127    * Listener for the operation to migrate from {@link FilteredNumberContract} blocking to {@link
128    * android.provider.BlockedNumberContract} blocking.
129    */
130   public interface Listener {
131 
132     /** Called when the migration operation is finished. */
onComplete()133     void onComplete();
134   }
135 
136   @TargetApi(VERSION_CODES.N)
137   private class MigratorTask extends AsyncTask<Void, Void, Boolean> {
138 
139     private final Listener listener;
140 
MigratorTask(Listener listener)141     public MigratorTask(Listener listener) {
142       this.listener = listener;
143     }
144 
145     @Override
doInBackground(Void... params)146     protected Boolean doInBackground(Void... params) {
147       LogUtil.i("BlockedNumbersMigrator.doInBackground", "migrate - start background migration");
148       return migrateToNewBlockingInBackground(context.getContentResolver());
149     }
150 
151     @Override
onPostExecute(Boolean isSuccessful)152     protected void onPostExecute(Boolean isSuccessful) {
153       LogUtil.i("BlockedNumbersMigrator.onPostExecute", "migrate - marking migration complete");
154       FilteredNumberCompat.setHasMigratedToNewBlocking(context, isSuccessful);
155       LogUtil.i("BlockedNumbersMigrator.onPostExecute", "migrate - calling listener");
156       listener.onComplete();
157     }
158   }
159 }
160