1 /* 2 * Copyright (C) 2016 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.incallui.legacyblocking; 18 19 import android.content.Context; 20 import android.database.ContentObserver; 21 import android.os.Handler; 22 import android.provider.CallLog; 23 import android.support.annotation.NonNull; 24 import com.android.dialer.common.LogUtil; 25 import com.android.dialer.common.concurrent.AsyncTaskExecutor; 26 import com.android.dialer.common.concurrent.AsyncTaskExecutors; 27 import com.android.dialer.util.PermissionsUtil; 28 import java.util.Objects; 29 30 /** 31 * Observes the {@link CallLog} to delete the CallLog entry for a blocked call after it is added. 32 * Automatically de-registers itself {@link #TIMEOUT_MS} ms after registration or if the entry is 33 * found and deleted. 34 */ 35 public class BlockedNumberContentObserver extends ContentObserver 36 implements DeleteBlockedCallTask.Listener { 37 38 /** 39 * The time after which a {@link BlockedNumberContentObserver} will be automatically unregistered. 40 */ 41 public static final int TIMEOUT_MS = 5000; 42 43 @NonNull private final Context context; 44 @NonNull private final Handler handler; 45 private final String number; 46 private final long timeAddedMillis; 47 private final Runnable timeoutRunnable = 48 new Runnable() { 49 @Override 50 public void run() { 51 unregister(); 52 } 53 }; 54 55 private final AsyncTaskExecutor asyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor(); 56 57 /** 58 * Creates the BlockedNumberContentObserver to delete the new {@link CallLog} entry from the given 59 * blocked number. 60 * 61 * @param number The blocked number. 62 * @param timeAddedMillis The time at which the call from the blocked number was placed. 63 */ 64 public BlockedNumberContentObserver( 65 @NonNull Context context, @NonNull Handler handler, String number, long timeAddedMillis) { 66 super(handler); 67 this.context = Objects.requireNonNull(context, "context").getApplicationContext(); 68 this.handler = Objects.requireNonNull(handler); 69 this.number = number; 70 this.timeAddedMillis = timeAddedMillis; 71 } 72 73 @Override 74 public void onChange(boolean selfChange) { 75 LogUtil.i( 76 "BlockedNumberContentObserver.onChange", 77 "attempting to remove call log entry from blocked number"); 78 asyncTaskExecutor.submit( 79 DeleteBlockedCallTask.IDENTIFIER, 80 new DeleteBlockedCallTask(context, this, number, timeAddedMillis)); 81 } 82 83 @Override 84 public void onDeleteBlockedCallTaskComplete(boolean didFindEntry) { 85 if (didFindEntry) { 86 unregister(); 87 } 88 } 89 90 /** 91 * Registers this {@link ContentObserver} to listen for changes to the {@link CallLog}. If the 92 * CallLog entry is not found before {@link #TIMEOUT_MS}, this ContentObserver automatically 93 * un-registers itself. 94 */ 95 public void register() { 96 LogUtil.i("BlockedNumberContentObserver.register", null); 97 if (PermissionsUtil.hasCallLogReadPermissions(context) 98 && PermissionsUtil.hasCallLogWritePermissions(context)) { 99 context.getContentResolver().registerContentObserver(CallLog.CONTENT_URI, true, this); 100 handler.postDelayed(timeoutRunnable, TIMEOUT_MS); 101 } else { 102 LogUtil.w("BlockedNumberContentObserver.register", "no call log read/write permissions."); 103 } 104 } 105 106 private void unregister() { 107 LogUtil.i("BlockedNumberContentObserver.unregister", null); 108 handler.removeCallbacks(timeoutRunnable); 109 context.getContentResolver().unregisterContentObserver(this); 110 } 111 } 112