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 
17 package android.permission2.cts;
18 
19 import android.app.Activity;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.pm.PackageManager;
26 import android.telephony.SmsManager;
27 import android.telephony.TelephonyManager;
28 import android.test.AndroidTestCase;
29 import android.util.Log;
30 
31 /**
32  * Verify Sms and Mms cannot be received without required permissions.
33  * Uses {@link android.telephony.SmsManager}.
34  */
35 public class NoReceiveSmsPermissionTest extends AndroidTestCase {
36 
37     // time to wait for sms to get delivered - currently 2 minutes
38     private static final int WAIT_TIME = 2*60*1000;
39     private static final String TELEPHONY_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
40     private static final String MESSAGE_STATUS_RECEIVED_ACTION =
41         "com.android.cts.permission.sms.MESSAGE_STATUS_RECEIVED_ACTION";
42     private static final String MESSAGE_SENT_ACTION =
43         "com.android.cts.permission.sms.MESSAGE_SENT";
44 
45     private static final String LOG_TAG = "NoReceiveSmsPermissionTest";
46 
47     /**
48      * Verify that SmsManager.sendTextMessage requires permissions.
49      * <p>Tests Permission:
50      *   {@link android.Manifest.permission#SEND_SMS}.
51      *
52      * Note: this test requires that the device under test reports a valid phone number
53      */
testReceiveTextMessage()54     public void testReceiveTextMessage() {
55         PackageManager packageManager = mContext.getPackageManager();
56         if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
57             return;
58         }
59 
60         // register our test receiver to receive SMSs. This won't throw a SecurityException,
61         // so test needs to wait to determine if it actual receives an SMS
62         // admittedly, this is a weak verification
63         // this test should be used in conjunction with a test that verifies an SMS can be
64         // received successfully using the same logic if all permissions are in place
65         IllegalSmsReceiver receiver = new IllegalSmsReceiver();
66         IntentFilter filter = new IntentFilter();
67         filter.addAction(TELEPHONY_SMS_RECEIVED);
68         filter.addAction(MESSAGE_SENT_ACTION);
69         filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
70 
71         getContext().registerReceiver(receiver, filter);
72         sendSMSToSelf();
73         synchronized(receiver) {
74             try {
75                 receiver.wait(WAIT_TIME);
76             } catch (InterruptedException e) {
77                 Log.w(LOG_TAG, "wait for sms interrupted");
78             }
79         }
80 
81         assertTrue("Sms not sent successfully, test environment problem?",
82                 receiver.isMessageSent());
83         assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
84     }
85 
sendSMSToSelf()86     private void sendSMSToSelf() {
87         PendingIntent sentIntent = PendingIntent.getBroadcast(getContext(), 0,
88                 new Intent(MESSAGE_SENT_ACTION), PendingIntent.FLAG_ONE_SHOT);
89         PendingIntent deliveryIntent = PendingIntent.getBroadcast(getContext(), 0,
90                 new Intent(MESSAGE_STATUS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT);
91 
92         TelephonyManager telephony = (TelephonyManager)
93                  getContext().getSystemService(Context.TELEPHONY_SERVICE);
94         // get current phone number
95         String currentNumber = telephony.getLine1Number();
96         Log.i(LOG_TAG, String.format("Sending SMS to self: %s", currentNumber));
97         sendSms(currentNumber, "test message", sentIntent, deliveryIntent);
98     }
99 
sendSms(String currentNumber, String text, PendingIntent sentIntent, PendingIntent deliveryIntent)100     protected void sendSms(String currentNumber, String text, PendingIntent sentIntent,
101             PendingIntent deliveryIntent) {
102         SmsManager.getDefault().sendTextMessage(currentNumber, null, text, sentIntent,
103                 deliveryIntent);
104     }
105 
106     /**
107      * A receiver that tracks if message was sent and received
108      */
109     public class IllegalSmsReceiver extends BroadcastReceiver {
110 
111         private boolean mIsSmsReceived = false;
112         private boolean mIsMessageSent = false;
113 
onReceive(Context context, Intent intent)114         public void onReceive(Context context, Intent intent) {
115             if (TELEPHONY_SMS_RECEIVED.equals(intent.getAction())) {
116                 // this is bad, received sms without having SMS permission
117                 setSmsReceived();
118             } else if (MESSAGE_STATUS_RECEIVED_ACTION.equals(intent.getAction())) {
119                 handleResultCode(getResultCode(), "delivery");
120             } else if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
121                 handleResultCode(getResultCode(), "sent");
122             } else {
123                 Log.w(LOG_TAG, String.format("unknown intent received: %s", intent.getAction()));
124             }
125 
126         }
127 
isSmsReceived()128         public boolean isSmsReceived() {
129             return mIsSmsReceived;
130         }
131 
setSmsReceived()132         private synchronized void setSmsReceived() {
133             mIsSmsReceived = true;
134             notify();
135         }
136 
isMessageSent()137         public boolean isMessageSent() {
138             return mIsMessageSent;
139         }
140 
handleResultCode(int resultCode, String action)141         private void handleResultCode(int resultCode, String action) {
142             if (resultCode == Activity.RESULT_OK) {
143                 Log.i(LOG_TAG, String.format("message %1$s successful", action));
144                 setMessageSentSuccess();
145             } else {
146                 setMessageSentFailure();
147                 String reason = getErrorReason(resultCode);
148                 Log.e(LOG_TAG, String.format("message %1$s failed: %2$s", action, reason));
149             }
150         }
151 
setMessageSentSuccess()152         private synchronized void setMessageSentSuccess() {
153             mIsMessageSent = true;
154             // set this to true, but don't notify receiver since we don't know if message received
155             // yet
156         }
157 
setMessageSentFailure()158         private synchronized void setMessageSentFailure() {
159             mIsMessageSent = false;
160             // test environment failure, notify observer so it can stop listening
161             // TODO: should test retry?
162             notify();
163         }
164 
getErrorReason(int resultCode)165         private String getErrorReason(int resultCode) {
166             switch (resultCode) {
167                 case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
168                     return "generic failure";
169                 case SmsManager.RESULT_ERROR_NO_SERVICE:
170                     return "no service";
171                 case SmsManager.RESULT_ERROR_NULL_PDU:
172                     return "null pdu";
173                 case SmsManager.RESULT_ERROR_RADIO_OFF:
174                     return "Radio off";
175             }
176             return "unknown";
177         }
178     }
179 }
180