1 /*
2  * Copyright (C) 2019 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.compatibility.common.util;
18 
19 import static android.provider.BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER;
20 import static android.provider.BlockedNumberContract.BlockedNumbers.CONTENT_URI;
21 
22 import android.app.IntentService;
23 import android.content.ContentResolver;
24 import android.content.ContentValues;
25 import android.content.Intent;
26 import android.database.ContentObserver;
27 import android.net.Uri;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.ResultReceiver;
31 import android.util.Log;
32 
33 import java.util.concurrent.CountDownLatch;
34 import java.util.concurrent.TimeUnit;
35 
36 /**
37  * A service to handle interactions with the BlockedNumberProvider. The BlockedNumberProvider
38  * can only be accessed by the primary user. This service can be run as a singleton service
39  * which will then be able to access the BlockedNumberProvider from a test running in a
40  * secondary user.
41  */
42 public class BlockedNumberService extends IntentService {
43 
44     static final String INSERT_ACTION = "android.telecom.cts.InsertBlockedNumber";
45     static final String DELETE_ACTION = "android.telecom.cts.DeleteBlockedNumber";
46     static final String PHONE_NUMBER_EXTRA = "number";
47     static final String URI_EXTRA = "uri";
48     static final String ROWS_EXTRA = "rows";
49     static final String FAIL_EXTRA = "fail";
50     static final String RESULT_RECEIVER_EXTRA = "resultReceiver";
51 
52     private static final String TAG = "CtsBlockNumberSvc";
53     private static final int ASYNC_TIMEOUT = 10000;
54 
55     private ContentResolver mContentResolver;
56     private Handler mHandler = new Handler();
57 
BlockedNumberService()58     public BlockedNumberService() {
59         super(BlockedNumberService.class.getName());
60     }
61 
62     @Override
onHandleIntent(Intent intent)63     public void onHandleIntent(Intent intent) {
64         Log.i(TAG, "Starting BlockedNumberService service: " + intent);
65         if (intent == null) {
66             return;
67         }
68         Bundle bundle;
69         mContentResolver = getContentResolver();
70         switch (intent.getAction()) {
71             case INSERT_ACTION:
72                 bundle = insertBlockedNumber(intent.getStringExtra(PHONE_NUMBER_EXTRA));
73                 break;
74             case DELETE_ACTION:
75                 bundle = deleteBlockedNumber(Uri.parse(intent.getStringExtra(URI_EXTRA)));
76                 break;
77             default:
78                 bundle = new Bundle();
79                 break;
80         }
81         ResultReceiver receiver = intent.getParcelableExtra(RESULT_RECEIVER_EXTRA);
82         receiver.send(0, bundle);
83     }
84 
insertBlockedNumber(String number)85     private Bundle insertBlockedNumber(String number) {
86         Log.i(TAG, "insertBlockedNumber: " + number);
87 
88         CountDownLatch blockedNumberLatch = getBlockedNumberLatch();
89         ContentValues cv = new ContentValues();
90         cv.put(COLUMN_ORIGINAL_NUMBER, number);
91         Uri uri = mContentResolver.insert(CONTENT_URI, cv);
92         Bundle bundle = new Bundle();
93         bundle.putString(URI_EXTRA, uri.toString());
94 
95         // Wait for the content provider to be updated.
96         try {
97             if (!blockedNumberLatch.await(ASYNC_TIMEOUT, TimeUnit.MILLISECONDS)) {
98                 Log.e(TAG, "Timed out waiting for blocked number update");
99                 bundle.putBoolean(FAIL_EXTRA, true);
100             }
101         } catch (InterruptedException e) {
102             Log.e(TAG, "Interrupted while waiting for blocked number update");
103             bundle.putBoolean(FAIL_EXTRA, true);
104         }
105         return bundle;
106     }
107 
getBlockedNumberLatch()108     private CountDownLatch getBlockedNumberLatch() {
109         CountDownLatch changeLatch = new CountDownLatch(1);
110         getContentResolver().registerContentObserver(
111                 CONTENT_URI, true,
112                     new ContentObserver(mHandler) {
113                         @Override
114                         public void onChange(boolean selfChange, Uri uri) {
115                             getContentResolver().unregisterContentObserver(this);
116                             changeLatch.countDown();
117                             super.onChange(selfChange);
118                         }
119                     });
120         return changeLatch;
121     }
122 
deleteBlockedNumber(Uri uri)123     private Bundle deleteBlockedNumber(Uri uri) {
124         Log.i(TAG, "deleteBlockedNumber: " + uri);
125 
126         int rows = mContentResolver.delete(uri, null, null);
127         Bundle bundle = new Bundle();
128         bundle.putInt(ROWS_EXTRA, rows);
129         return bundle;
130     }
131 }
132