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.app.calllog;
18 
19 import android.content.ContentValues;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.net.Uri;
23 import android.os.AsyncTask;
24 import android.provider.CallLog;
25 import android.provider.VoicemailContract.Voicemails;
26 import android.support.annotation.NonNull;
27 import android.support.annotation.Nullable;
28 import android.text.TextUtils;
29 import com.android.dialer.common.LogUtil;
30 import com.android.dialer.common.concurrent.AsyncTaskExecutor;
31 import com.android.dialer.common.concurrent.AsyncTaskExecutors;
32 import com.android.dialer.util.PermissionsUtil;
33 import com.android.voicemail.VoicemailClient;
34 
35 /** TODO(calderwoodra): documentation */
36 public class CallLogAsyncTaskUtil {
37 
38   private static final String TAG = "CallLogAsyncTaskUtil";
39   private static AsyncTaskExecutor asyncTaskExecutor;
40 
initTaskExecutor()41   private static void initTaskExecutor() {
42     asyncTaskExecutor = AsyncTaskExecutors.createThreadPoolExecutor();
43   }
44 
markVoicemailAsRead( @onNull final Context context, @NonNull final Uri voicemailUri)45   public static void markVoicemailAsRead(
46       @NonNull final Context context, @NonNull final Uri voicemailUri) {
47     LogUtil.enterBlock("CallLogAsyncTaskUtil.markVoicemailAsRead, voicemailUri: " + voicemailUri);
48     if (asyncTaskExecutor == null) {
49       initTaskExecutor();
50     }
51 
52     asyncTaskExecutor.submit(
53         Tasks.MARK_VOICEMAIL_READ,
54         new AsyncTask<Void, Void, Void>() {
55           @Override
56           public Void doInBackground(Void... params) {
57             ContentValues values = new ContentValues();
58             values.put(Voicemails.IS_READ, true);
59             // "External" changes to the database will be automatically marked as dirty, but this
60             // voicemail might be from dialer so it need to be marked manually.
61             values.put(Voicemails.DIRTY, 1);
62             if (context
63                     .getContentResolver()
64                     .update(voicemailUri, values, Voicemails.IS_READ + " = 0", null)
65                 > 0) {
66               uploadVoicemailLocalChangesToServer(context);
67               CallLogNotificationsService.markAllNewVoicemailsAsOld(context);
68             }
69             return null;
70           }
71         });
72   }
73 
deleteVoicemail( @onNull final Context context, final Uri voicemailUri, @Nullable final CallLogAsyncTaskListener callLogAsyncTaskListener)74   public static void deleteVoicemail(
75       @NonNull final Context context,
76       final Uri voicemailUri,
77       @Nullable final CallLogAsyncTaskListener callLogAsyncTaskListener) {
78     if (asyncTaskExecutor == null) {
79       initTaskExecutor();
80     }
81 
82     asyncTaskExecutor.submit(
83         Tasks.DELETE_VOICEMAIL,
84         new AsyncTask<Void, Void, Void>() {
85           @Override
86           public Void doInBackground(Void... params) {
87             deleteVoicemailSynchronous(context, voicemailUri);
88             return null;
89           }
90 
91           @Override
92           public void onPostExecute(Void result) {
93             if (callLogAsyncTaskListener != null) {
94               callLogAsyncTaskListener.onDeleteVoicemail();
95             }
96           }
97         });
98   }
99 
deleteVoicemailSynchronous(Context context, Uri voicemailUri)100   public static void deleteVoicemailSynchronous(Context context, Uri voicemailUri) {
101     ContentValues values = new ContentValues();
102     values.put(Voicemails.DELETED, "1");
103     context.getContentResolver().update(voicemailUri, values, null, null);
104     // TODO(a bug): check which source package is changed. Don't need
105     // to upload changes on foreign voicemails, they will get a PROVIDER_CHANGED
106     uploadVoicemailLocalChangesToServer(context);
107   }
108 
markCallAsRead(@onNull final Context context, @NonNull final long[] callIds)109   public static void markCallAsRead(@NonNull final Context context, @NonNull final long[] callIds) {
110     if (!PermissionsUtil.hasPhonePermissions(context)
111         || !PermissionsUtil.hasCallLogWritePermissions(context)) {
112       return;
113     }
114     if (asyncTaskExecutor == null) {
115       initTaskExecutor();
116     }
117 
118     asyncTaskExecutor.submit(
119         Tasks.MARK_CALL_READ,
120         new AsyncTask<Void, Void, Void>() {
121           @Override
122           public Void doInBackground(Void... params) {
123 
124             StringBuilder where = new StringBuilder();
125             where.append(CallLog.Calls.TYPE).append(" = ").append(CallLog.Calls.MISSED_TYPE);
126             where.append(" AND ");
127 
128             Long[] callIdLongs = new Long[callIds.length];
129             for (int i = 0; i < callIds.length; i++) {
130               callIdLongs[i] = callIds[i];
131             }
132             where
133                 .append(CallLog.Calls._ID)
134                 .append(" IN (" + TextUtils.join(",", callIdLongs) + ")");
135 
136             ContentValues values = new ContentValues(1);
137             values.put(CallLog.Calls.IS_READ, "1");
138             context
139                 .getContentResolver()
140                 .update(CallLog.Calls.CONTENT_URI, values, where.toString(), null);
141             return null;
142           }
143         });
144   }
145 
146   /** The enumeration of {@link AsyncTask} objects used in this class. */
147   public enum Tasks {
148     DELETE_VOICEMAIL,
149     DELETE_CALL,
150     MARK_VOICEMAIL_READ,
151     MARK_CALL_READ,
152     GET_CALL_DETAILS,
153     UPDATE_DURATION,
154   }
155 
156   /** TODO(calderwoodra): documentation */
157   public interface CallLogAsyncTaskListener {
onDeleteVoicemail()158     void onDeleteVoicemail();
159   }
160 
uploadVoicemailLocalChangesToServer(Context context)161   private static void uploadVoicemailLocalChangesToServer(Context context) {
162     Intent intent = new Intent(VoicemailClient.ACTION_UPLOAD);
163     intent.setPackage(context.getPackageName());
164     context.sendBroadcast(intent);
165   }
166 }
167