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