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 android.telecom.cts;
18 
19 import android.content.ComponentName;
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.os.Process;
26 import android.provider.VoicemailContract.Voicemails;
27 import android.support.test.uiautomator.By;
28 import android.support.test.uiautomator.UiDevice;
29 import android.support.test.uiautomator.Until;
30 import android.telecom.PhoneAccountHandle;
31 import android.telecom.TelecomManager;
32 import android.test.InstrumentationTestCase;
33 import android.text.TextUtils;
34 
35 import androidx.test.InstrumentationRegistry;
36 import com.android.compatibility.common.util.ShellIdentityUtils;
37 
38 import java.util.List;
39 
40 
41 /**
42  * Verifies that certain privileged operations can only be performed by the default dialer.
43  */
44 public class DefaultDialerOperationsTest extends InstrumentationTestCase {
45     private static final int ACTIVITY_LAUNCHING_TIMEOUT_MILLIS = 20000;  // 20 seconds
46     private static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
47 
48     private Context mContext;
49     private UiDevice mUiDevice;
50     private TelecomManager mTelecomManager;
51     private PackageManager mPackageManager;
52     private PhoneAccountHandle mPhoneAccountHandle;
53     private String mPreviousDefaultDialer = null;
54     private String mSystemDialer = null;
55 
56     @Override
setUp()57     protected void setUp() throws Exception {
58         super.setUp();
59         mContext = getInstrumentation().getContext();
60         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
61 
62         if (!TestUtils.shouldTestTelecom(mContext)) {
63             return;
64         }
65         mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
66         // Reset the current dialer to the system dialer, to ensure that we start each test
67         // without being the default dialer.
68         mSystemDialer = TestUtils.getSystemDialer(getInstrumentation());
69         if (!TextUtils.isEmpty(mSystemDialer)) {
70             TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
71         }
72         mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
73         mPackageManager = mContext.getPackageManager();
74         final List<PhoneAccountHandle> accounts = mTelecomManager.getCallCapablePhoneAccounts();
75         if (accounts != null && !accounts.isEmpty()) {
76             mPhoneAccountHandle = accounts.get(0);
77         }
78     }
79 
80     @Override
tearDown()81     protected void tearDown() throws Exception {
82         if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
83             // Restore the default dialer to whatever the default dialer was before the tests
84             // were started. This may or may not be the system dialer.
85             TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
86         }
87         super.tearDown();
88     }
89 
testGetDefaultDialerPackage()90     public void testGetDefaultDialerPackage() throws Exception {
91         if (!TestUtils.shouldTestTelecom(mContext)) {
92             return;
93         }
94         assertEquals(mSystemDialer, mTelecomManager.getDefaultDialerPackage());
95         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
96         assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
97         assertEquals(mTelecomManager.getDefaultDialerPackage(),
98                 ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
99                         tm -> tm.getDefaultDialerPackage(Process.myUserHandle())));
100     }
101 
102     /** Default dialer should be the default package handling ACTION_DIAL. */
testActionDialHandling()103     public void testActionDialHandling() throws Exception {
104         if (!TestUtils.shouldTestTelecom(mContext) || !TestUtils.hasTelephonyFeature(mContext)) {
105             return;
106         }
107         Intent intent = new Intent(Intent.ACTION_DIAL);
108         ResolveInfo info =
109                 mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
110         assertEquals(info.activityInfo.packageName, mTelecomManager.getDefaultDialerPackage());
111     }
112 
113     /** The package handling Intent ACTION_DIAL should be the same package showing the UI. */
testDialerUI()114     public void testDialerUI() throws Exception {
115         if (!TestUtils.shouldTestTelecom(mContext)) {
116             return;
117         }
118         // Find which package handling the intent
119         Intent intent = new Intent(Intent.ACTION_DIAL);
120         ResolveInfo info =
121                 mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
122         assertTrue(info != null); // Default dialer should always handle it
123 
124         verifySamePackageForIntentHandlingAndUI(intent, info);
125     }
126 
127     /** The package handling Intent emergency dail should be the same package showing the UI. */
testEmergencyDialerUI()128     public void testEmergencyDialerUI() throws Exception {
129         if (!TestUtils.shouldTestTelecom(mContext)) {
130             return;
131         }
132         // Find which package handling the intent
133         Intent intent = new Intent(ACTION_EMERGENCY_DIAL);
134         ResolveInfo info =
135                 mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
136         if (info == null) {
137             // Skip the test if no package handles ACTION_EMERGENCY_DIAL
138             return;
139         }
140 
141         verifySamePackageForIntentHandlingAndUI(intent, info);
142     }
143 
testVoicemailReadWritePermissions()144     public void testVoicemailReadWritePermissions() throws Exception {
145         if (!TestUtils.shouldTestTelecom(mContext)) {
146             return;
147         }
148         try {
149             mContext.getContentResolver().query(Voicemails.CONTENT_URI, null, null, null, null);
150             fail("Reading voicemails should throw SecurityException if not default Dialer");
151         } catch (SecurityException e) {
152         }
153 
154         try {
155             mContext.getContentResolver().delete(Voicemails.CONTENT_URI,
156                     Voicemails._ID + "=999 AND 1=2", null);
157             fail("Deleting voicemails should throw SecurityException if not default Dialer");
158         } catch (SecurityException e) {
159         }
160 
161         try {
162             mContext.getContentResolver().update(
163                     Voicemails.CONTENT_URI.buildUpon().appendPath("999").build(),
164                     new ContentValues(),
165                     null,
166                     null);
167             fail("Updating voicemails should throw SecurityException if not default Dialer");
168         } catch (SecurityException e) {
169         }
170 
171         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
172         // No exception if the calling package is the default dialer.
173         mContext.getContentResolver().query(Voicemails.CONTENT_URI, null, null, null, null);
174         mContext.getContentResolver().delete(Voicemails.CONTENT_URI,
175                 Voicemails._ID + "=999 AND 1=2", null);
176     }
177 
testSilenceRingerPermissions()178     public void testSilenceRingerPermissions() throws Exception {
179         if (!TestUtils.shouldTestTelecom(mContext)) {
180             return;
181         }
182         try {
183             mTelecomManager.silenceRinger();
184             fail("TelecomManager.silenceRinger should throw SecurityException if not default "
185                     + "dialer");
186         } catch (SecurityException e) {
187         }
188 
189         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
190         // No exception if the calling package is the default dialer.
191         mTelecomManager.silenceRinger();
192     }
193 
testCancelMissedCallsNotificationPermissions()194     public void testCancelMissedCallsNotificationPermissions()
195             throws Exception {
196         if (!TestUtils.shouldTestTelecom(mContext)) {
197             return;
198         }
199         try {
200             mTelecomManager.cancelMissedCallsNotification();
201             fail("TelecomManager.cancelMissedCallsNotification should throw SecurityException if "
202                     + "not default dialer");
203         } catch (SecurityException e) {
204         }
205 
206         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
207         // No exception if the calling package is the default dialer.
208         mTelecomManager.cancelMissedCallsNotification();
209     }
210 
testHandlePinMmPermissions()211     public void testHandlePinMmPermissions()
212             throws Exception {
213         if (!TestUtils.shouldTestTelecom(mContext)) {
214             return;
215         }
216         try {
217             mTelecomManager.handleMmi("0");
218             fail("TelecomManager.handleMmi should throw SecurityException if not default dialer");
219         } catch (SecurityException e) {
220         }
221 
222         try {
223             mTelecomManager.handleMmi("0", mPhoneAccountHandle);
224             fail("TelecomManager.handleMmi should throw SecurityException if not default dialer");
225         } catch (SecurityException e) {
226         }
227 
228         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
229         // No exception if the calling package is the default dialer.
230         mTelecomManager.handleMmi("0");
231         mTelecomManager.handleMmi("0", mPhoneAccountHandle);
232     }
233 
testGetAdnForPhoneAccountPermissions()234     public void testGetAdnForPhoneAccountPermissions() throws Exception {
235         if (!TestUtils.shouldTestTelecom(mContext)) {
236             return;
237         }
238         try {
239             mTelecomManager.getAdnUriForPhoneAccount(mPhoneAccountHandle);
240             fail("TelecomManager.getAdnUriForPhoneAccount should throw SecurityException if "
241                     + "not default dialer");
242         } catch (SecurityException e) {
243         }
244 
245         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
246         // No exception if the calling package is the default dialer.
247         mTelecomManager.getAdnUriForPhoneAccount(mPhoneAccountHandle);
248     }
249 
250     /**
251      * TODO: Re-enable this test when CTS tests are refactored.
252      * @throws Exception
253      */
donotTestSetDefaultDialerNoDialIntent_notSupported()254     public void donotTestSetDefaultDialerNoDialIntent_notSupported() throws Exception {
255         if (!TestUtils.shouldTestTelecom(mContext)) {
256             return;
257         }
258         final ComponentName name = new ComponentName(mContext,
259                 "android.telecom.cts.MockDialerActivity");
260         try {
261             mPackageManager.setComponentEnabledSetting(
262                     name,
263                     PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
264                     PackageManager.DONT_KILL_APP);
265             TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
266             final String result = TestUtils.getDefaultDialer(getInstrumentation());
267             assertNotSame(result, TestUtils.PACKAGE);
268             assertTrue("Expected failure indicating that this was not an installed dialer app",
269                     result.contains("is not an installed Dialer app"));
270         } finally {
271             mPackageManager.setComponentEnabledSetting(
272                     name,
273                     PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
274                     PackageManager.DONT_KILL_APP);
275         }
276 
277         // Now that the activity is present again in the package manager, this should succeed.
278         TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
279         final String result = TestUtils.getDefaultDialer(getInstrumentation());
280         assertTrue("Expected success message indicating that " + TestUtils.PACKAGE + " was set as "
281                 + "default dialer.", result.contains("set as default dialer"));
282         assertEquals(TestUtils.PACKAGE, TestUtils.getDefaultDialer(getInstrumentation()));
283     }
284 
285     /**
286      * Verifies that the {@link TelecomManager#getSystemDialerPackage()} API returns the correct
287      * package name for the preloaded system dialer app.
288      */
testGetSystemDialer()289     public void testGetSystemDialer() throws Exception {
290         if (!TestUtils.shouldTestTelecom(mContext)) {
291             return;
292         }
293         String reportedDialer = mTelecomManager.getSystemDialerPackage();
294         assertEquals(mSystemDialer, reportedDialer);
295     }
296 
verifySamePackageForIntentHandlingAndUI(Intent intent, ResolveInfo info)297     private void verifySamePackageForIntentHandlingAndUI(Intent intent, ResolveInfo info) {
298         String packageName = info.activityInfo.packageName;
299         assertTrue(!TextUtils.isEmpty(packageName));
300 
301         mUiDevice.pressHome();
302         mUiDevice.waitForIdle();
303         try {
304             mContext.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
305 
306             // The package handles the intent should be foreground
307             mUiDevice.wait(
308                     Until.hasObject(By.pkg(packageName).depth(0)),
309                     ACTIVITY_LAUNCHING_TIMEOUT_MILLIS);
310             mUiDevice.waitForIdle();
311         } finally {
312             mUiDevice.pressHome();
313             mUiDevice.waitForIdle();
314         }
315     }
316 }
317