1 /*
2  * Copyright (C) 2017 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 package com.android.voicemail.impl.transcribe;
17 
18 import android.app.job.JobInfo;
19 import android.app.job.JobScheduler;
20 import android.app.job.JobWorkItem;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.net.Uri;
25 import android.os.Bundle;
26 import android.support.annotation.WorkerThread;
27 import android.support.v4.app.JobIntentService;
28 import android.support.v4.os.BuildCompat;
29 import android.telecom.PhoneAccountHandle;
30 import com.android.dialer.common.LogUtil;
31 import com.android.dialer.common.concurrent.ThreadUtil;
32 import com.android.dialer.constants.ScheduledJobIds;
33 import java.util.List;
34 
35 /**
36  * JobScheduler service for transcribing old voicemails. This service does a database scan for
37  * un-transcribed voicemails and schedules transcription tasks for them, once we have an un-metered
38  * network connection.
39  */
40 public class TranscriptionBackfillService extends JobIntentService {
41 
42   /** Schedule a task to scan the database for untranscribed voicemails */
scheduleTask(Context context, PhoneAccountHandle account)43   public static boolean scheduleTask(Context context, PhoneAccountHandle account) {
44     if (BuildCompat.isAtLeastO()) {
45       LogUtil.enterBlock("TranscriptionBackfillService.transcribeOldVoicemails");
46       ComponentName componentName = new ComponentName(context, TranscriptionBackfillService.class);
47       JobInfo.Builder builder =
48           new JobInfo.Builder(ScheduledJobIds.VVM_TRANSCRIPTION_BACKFILL_JOB, componentName)
49               .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
50       JobScheduler scheduler = context.getSystemService(JobScheduler.class);
51       return scheduler.enqueue(builder.build(), makeWorkItem(account))
52           == JobScheduler.RESULT_SUCCESS;
53     } else {
54       LogUtil.i("TranscriptionBackfillService.transcribeOldVoicemails", "not supported");
55       return false;
56     }
57   }
58 
makeWorkItem(PhoneAccountHandle account)59   private static JobWorkItem makeWorkItem(PhoneAccountHandle account) {
60     Intent intent = new Intent();
61     intent.putExtra(TranscriptionService.EXTRA_ACCOUNT_HANDLE, account);
62     return new JobWorkItem(intent);
63   }
64 
65   @Override
66   @WorkerThread
onHandleWork(Intent intent)67   protected void onHandleWork(Intent intent) {
68     LogUtil.enterBlock("TranscriptionBackfillService.onHandleWork");
69 
70     Bundle bundle = intent.getExtras();
71     final PhoneAccountHandle account =
72         (PhoneAccountHandle) bundle.get(TranscriptionService.EXTRA_ACCOUNT_HANDLE);
73 
74     TranscriptionDbHelper dbHelper = new TranscriptionDbHelper(this);
75     List<Uri> untranscribed = dbHelper.getUntranscribedVoicemails();
76     LogUtil.i(
77         "TranscriptionBackfillService.onHandleWork",
78         "found " + untranscribed.size() + " untranscribed voicemails");
79     // TODO(mdooley): Consider doing the actual transcriptions here instead of scheduling jobs.
80     for (Uri uri : untranscribed) {
81       ThreadUtil.postOnUiThread(
82           () -> {
83             TranscriptionService.scheduleNewVoicemailTranscriptionJob(this, uri, account, false);
84           });
85     }
86   }
87 
88   @Override
onDestroy()89   public void onDestroy() {
90     LogUtil.enterBlock("TranscriptionBackfillService.onDestroy");
91     super.onDestroy();
92   }
93 }
94