1 /*
2  * Copyright (C) 2010 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.phone.common;
18 import android.content.Context;
19 import android.os.AsyncTask;
20 import android.os.Looper;
21 import android.provider.CallLog.Calls;
22 
23 /**
24  * Class to access the call log asynchronously to avoid carrying out database operations on the
25  * UI thread, using an {@link AsyncTask}.
26  *
27  * <pre class="prettyprint">
28  * Typical usage:
29  * ==============
30  *
31  *  // From an activity...
32  *  String mLastNumber = "";
33  *
34  *  CallLogAsync log = new CallLogAsync();
35  *
36  *  CallLogAsync.GetLastOutgoingCallArgs lastCallArgs = new CallLogAsync.GetLastOutgoingCallArgs(
37  *      this, new CallLogAsync.OnLastOutgoingCallComplete() {
38  *               public void lastOutgoingCall(String number) { mLastNumber = number; }
39  *            });
40  *  log.getLastOutgoingCall(lastCallArgs);
41  * </pre>
42  *
43  */
44 
45 public class CallLogAsync {
46     private static final String TAG = "CallLogAsync";
47 
48     /**
49      * Parameter object to hold the args to get the last outgoing call
50      * from the call log DB.
51      */
52     public static class GetLastOutgoingCallArgs {
GetLastOutgoingCallArgs(Context context, OnLastOutgoingCallComplete callback)53         public GetLastOutgoingCallArgs(Context context,
54                                        OnLastOutgoingCallComplete callback) {
55             this.context = context;
56             this.callback = callback;
57         }
58         public final Context context;
59         public final OnLastOutgoingCallComplete callback;
60     }
61 
62     /** Interface to retrieve the last dialed number asynchronously. */
63     public interface OnLastOutgoingCallComplete {
64         /** @param number The last dialed number or an empty string if
65          *                none exists yet. */
lastOutgoingCall(String number)66         void lastOutgoingCall(String number);
67     }
68 
69     /**
70      * CallLog.getLastOutgoingCall(...)
71      */
getLastOutgoingCall(GetLastOutgoingCallArgs args)72     public AsyncTask getLastOutgoingCall(GetLastOutgoingCallArgs args) {
73         assertUiThread();
74         return new GetLastOutgoingCallTask(args.callback).execute(args);
75     }
76 
77     /**
78      * AsyncTask to get the last outgoing call from the DB.
79      */
80     private class GetLastOutgoingCallTask extends AsyncTask<GetLastOutgoingCallArgs, Void, String> {
81         private final OnLastOutgoingCallComplete mCallback;
82         private String mNumber;
GetLastOutgoingCallTask(OnLastOutgoingCallComplete callback)83         public GetLastOutgoingCallTask(OnLastOutgoingCallComplete callback) {
84             mCallback = callback;
85         }
86 
87         // Happens on a background thread. We cannot run the callback
88         // here because only the UI thread can modify the view
89         // hierarchy (e.g enable/disable the dial button). The
90         // callback is ran rom the post execute method.
91         @Override
doInBackground(GetLastOutgoingCallArgs... list)92         protected String doInBackground(GetLastOutgoingCallArgs... list) {
93             int count = list.length;
94             String number = "";
95             for (GetLastOutgoingCallArgs args : list) {
96                 // May block. Select only the last one.
97                 number = Calls.getLastOutgoingCall(args.context);
98             }
99             return number;  // passed to the onPostExecute method.
100         }
101 
102         // Happens on the UI thread, it is safe to run the callback
103         // that may do some work on the views.
104         @Override
onPostExecute(String number)105         protected void onPostExecute(String number) {
106             assertUiThread();
107             mCallback.lastOutgoingCall(number);
108         }
109     }
110 
assertUiThread()111     private void assertUiThread() {
112         if (!Looper.getMainLooper().equals(Looper.myLooper())) {
113             throw new RuntimeException("Not on the UI thread!");
114         }
115     }
116 }
117