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