1/*
2 * Copyright (C) 2009 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.internal.telephony;
18
19import android.test.AndroidTestCase;
20import android.test.suitebuilder.annotation.SmallTest;
21
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.res.Resources;
25import com.android.internal.telephony.CallerInfo;
26import com.android.internal.telephony.CallerInfoAsyncQuery;
27import android.util.Log;
28import android.os.Looper;
29import android.test.ActivityInstrumentationTestCase;
30import android.util.StringBuilderPrinter;
31
32/*
33 * Check the CallerInfo utility class works as expected.
34 *
35 */
36
37public class CallerInfoTest extends AndroidTestCase {
38    private CallerInfo mInfo;
39    private Context mContext;
40
41    private static final String kEmergencyNumber = "Emergency Number";
42    private static final int kToken = 0xdeadbeef;
43    private static final String TAG = "CallerInfoUnitTest";
44
45    @Override
46    protected void setUp() throws Exception {
47        super.setUp();
48        mContext = new MockContext();
49        mInfo = new CallerInfo();
50    }
51
52    @Override
53    protected void tearDown() throws Exception {
54        super.tearDown();
55    }
56
57    /**
58     * Checks the caller info instance is flagged as an emergency if
59     * the number is an emergency one. There is no test for the
60     * contact based constructors because emergency number are not in
61     * the contact DB.
62     */
63    @SmallTest
64    public void testEmergencyIsProperlySet() throws Exception {
65        assertFalse(mInfo.isEmergencyNumber());
66
67        mInfo = CallerInfo.getCallerInfo(mContext, "911");
68        assertIsValidEmergencyCallerInfo();
69
70        mInfo = CallerInfo.getCallerInfo(mContext, "tel:911");
71        assertIsValidEmergencyCallerInfo();
72
73
74        // This one hits the content resolver.
75        mInfo = CallerInfo.getCallerInfo(mContext, "18001234567");
76        assertFalse(mInfo.isEmergencyNumber());
77    }
78
79    /**
80     * Same as testEmergencyIsProperlySet but uses the async query api.
81     */
82    @SmallTest
83    public void testEmergencyIsProperlySetUsingAsyncQuery() throws Exception {
84        QueryRunner query;
85
86        query = new QueryRunner("911");
87        query.runAndCheckCompletion();
88        assertIsValidEmergencyCallerInfo();
89
90        query = new QueryRunner("tel:911");
91        query.runAndCheckCompletion();
92        assertIsValidEmergencyCallerInfo();
93
94        query = new QueryRunner("18001234567");
95        query.runAndCheckCompletion();
96        assertFalse(mInfo.isEmergencyNumber());
97    }
98
99    /**
100     * For emergency caller info, phoneNumber should be set to the
101     * string emergency_call_dialog_number_for_display and the
102     * photoResource should be set to the picture_emergency drawable.
103     */
104    @SmallTest
105    public void testEmergencyNumberAndPhotoAreSet() throws Exception {
106        mInfo = CallerInfo.getCallerInfo(mContext, "911");
107
108        assertIsValidEmergencyCallerInfo();
109    }
110
111    // TODO: Add more tests:
112    /**
113     * Check if the voice mail number cannot be retrieved that the
114     * original phone number is preserved.
115     */
116    /**
117     * Check the markAs* methods work.
118     */
119
120
121    //
122    // Helpers
123    //
124
125    // Partial implementation of MockResources.
126    public class MockResources extends android.test.mock.MockResources
127    {
128        @Override
129        public String getString(int resId) throws Resources.NotFoundException {
130            switch (resId) {
131                case com.android.internal.R.string.emergency_call_dialog_number_for_display:
132                    return kEmergencyNumber;
133                default:
134                    throw new UnsupportedOperationException("Missing handling for resid " + resId);
135            }
136        }
137    }
138
139    // Partial implementation of MockContext.
140    public class MockContext extends android.test.mock.MockContext {
141        private ContentResolver mResolver;
142        private Resources mResources;
143
144        public MockContext() {
145            mResolver = new android.test.mock.MockContentResolver();
146            mResources = new MockResources();
147        }
148
149        @Override
150        public ContentResolver getContentResolver() {
151            return mResolver;
152        }
153
154        @Override
155        public Resources getResources() {
156            return mResources;
157        }
158    }
159
160    /**
161     * Class to run a CallerInfoAsyncQuery in a separate thread, with
162     * its own Looper. We cannot use the main Looper because on the
163     * 1st quit the thread is maked dead, ie no further test can use
164     * it. Also there is not way to inject a Looper instance in the
165     * query, so we have to use a thread with its own looper.
166     */
167    private class QueryRunner extends Thread
168            implements CallerInfoAsyncQuery.OnQueryCompleteListener {
169        private Looper mLooper;
170        private String mNumber;
171        private boolean mAsyncCompleted;
172
173        public QueryRunner(String number) {
174            super();
175            mNumber = number;
176        }
177
178        // Run the query in the thread, wait for completion.
179        public void runAndCheckCompletion() throws InterruptedException {
180            start();
181            join();
182            assertTrue(mAsyncCompleted);
183        }
184
185        @Override
186        public void run() {
187            Looper.prepare();
188            mLooper = Looper.myLooper();
189            mAsyncCompleted = false;
190            // The query will pick the thread local looper we've just prepared.
191            CallerInfoAsyncQuery.startQuery(kToken, mContext, mNumber, this, null);
192            mLooper.loop();
193        }
194
195        // Quit the Looper on the 1st callback
196        // (EVENT_EMERGENCY_NUMBER). There is another message
197        // (EVENT_END_OF_QUEUE) that will never be delivered because
198        // the test has exited. The corresponding stack trace
199        // "Handler{xxxxx} sending message to a Handler on a dead
200        // thread" can be ignored.
201        public void onQueryComplete(int token, Object cookie, CallerInfo info) {
202            mAsyncCompleted = true;
203            mInfo = info;
204            mLooper.quit();
205        }
206    }
207
208    /**
209     * Fail if mInfo does not contain a valid emergency CallerInfo instance.
210     */
211    private void assertIsValidEmergencyCallerInfo() throws Exception {
212        assertTrue(mInfo.isEmergencyNumber());
213
214        // For emergency caller info, phoneNumber should be set to the
215        // string emergency_call_dialog_number_for_display and the
216        // photoResource should be set to the picture_emergency drawable.
217        assertEquals(kEmergencyNumber, mInfo.phoneNumber);
218        assertEquals(com.android.internal.R.drawable.picture_emergency, mInfo.photoResource);
219
220        // The name should be null
221        assertNull(mInfo.name);
222        assertEquals(0, mInfo.namePresentation);
223        assertNull(mInfo.cnapName);
224        assertEquals(0, mInfo.numberPresentation);
225
226        assertFalse(mInfo.contactExists);
227        assertEquals(0, mInfo.person_id);
228        assertFalse(mInfo.needUpdate);
229        assertNull(mInfo.contactRefUri);
230
231        assertNull(mInfo.phoneLabel);
232        assertEquals(0, mInfo.numberType);
233        assertNull(mInfo.numberLabel);
234
235        assertNull(mInfo.contactRingtoneUri);
236        assertFalse(mInfo.shouldSendToVoicemail);
237
238        assertNull(mInfo.cachedPhoto);
239        assertFalse(mInfo.isCachedPhotoCurrent);
240    }
241}
242