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    */
BlockedNumberContentObserver( @onNull Context context, @NonNull Handler handler, String number, long timeAddedMillis)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
onChange(boolean selfChange)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
onDeleteBlockedCallTaskComplete(boolean didFindEntry)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    */
register()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 
unregister()106   private void unregister() {
107     LogUtil.i("BlockedNumberContentObserver.unregister", null);
108     handler.removeCallbacks(timeoutRunnable);
109     context.getContentResolver().unregisterContentObserver(this);
110   }
111 }
112