blob: 5699d88d5963577232690d816fa9a852be45882e [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.permission2.cts;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.test.AndroidTestCase;
import android.text.TextUtils;
import android.util.Log;
/**
* Verify Sms and Mms cannot be received without required permissions.
* Uses {@link android.telephony.SmsManager}.
*/
public class NoReceiveSmsPermissionTest extends AndroidTestCase {
// time to wait for sms to get delivered - currently 2 minutes
private static final int WAIT_TIME = 2*60*1000;
private static final String TELEPHONY_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static final String MESSAGE_STATUS_RECEIVED_ACTION =
"com.android.cts.permission.sms.MESSAGE_STATUS_RECEIVED_ACTION";
private static final String MESSAGE_SENT_ACTION =
"com.android.cts.permission.sms.MESSAGE_SENT";
private static final String APP_SPECIFIC_SMS_RECEIVED_ACTION =
"com.android.cts.permission.sms.APP_SPECIFIC_SMS_RECEIVED";
private static final String LOG_TAG = "NoReceiveSmsPermissionTest";
/**
* Verify that SmsManager.sendTextMessage requires permissions.
* <p>Tests Permission:
* {@link android.Manifest.permission#SEND_SMS}.
*
* Note: this test requires that the device under test reports a valid phone number
*/
public void testReceiveTextMessage() {
PackageManager packageManager = mContext.getPackageManager();
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
// register our test receiver to receive SMSs. This won't throw a SecurityException,
// so test needs to wait to determine if it actual receives an SMS
// admittedly, this is a weak verification
// this test should be used in conjunction with a test that verifies an SMS can be
// received successfully using the same logic if all permissions are in place
IllegalSmsReceiver receiver = new IllegalSmsReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(TELEPHONY_SMS_RECEIVED);
filter.addAction(MESSAGE_SENT_ACTION);
filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
getContext().registerReceiver(receiver, filter);
sendSMSToSelf("test");
synchronized(receiver) {
try {
receiver.wait(WAIT_TIME);
} catch (InterruptedException e) {
Log.w(LOG_TAG, "wait for sms interrupted");
}
}
assertTrue("[RERUN] Sms not sent successfully. Check signal.",
receiver.isMessageSent());
assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
}
/**
* Verify that without {@link android.Manifest.permission#RECEIVE_SMS} that an SMS sent
* containing a nonce from {@link SmsManager#createAppSpecificSmsToken} is delivered
* to the app.
*/
public void testAppSpecificSmsToken() {
PackageManager packageManager = mContext.getPackageManager();
if (!packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
return;
}
AppSpecificSmsReceiver receiver = new AppSpecificSmsReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(TELEPHONY_SMS_RECEIVED);
filter.addAction(MESSAGE_SENT_ACTION);
filter.addAction(MESSAGE_STATUS_RECEIVED_ACTION);
filter.addAction(APP_SPECIFIC_SMS_RECEIVED_ACTION);
getContext().registerReceiver(receiver, filter);
PendingIntent receivedIntent = PendingIntent.getBroadcast(getContext(), 0,
new Intent(APP_SPECIFIC_SMS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT);
String token = SmsManager.getDefault().createAppSpecificSmsToken(receivedIntent);
String message = "test message, token=" + token;
sendSMSToSelf(message);
synchronized(receiver) {
try {
receiver.wait(WAIT_TIME);
} catch (InterruptedException e) {
Log.w(LOG_TAG, "wait for sms interrupted");
}
}
assertTrue("[RERUN] Sms not sent successfully. Check signal.",
receiver.isMessageSent());
assertFalse("Sms received without proper permissions", receiver.isSmsReceived());
assertTrue("App specific SMS intent not triggered", receiver.isAppSpecificSmsReceived());
}
private void sendSMSToSelf(String message) {
PendingIntent sentIntent = PendingIntent.getBroadcast(getContext(), 0,
new Intent(MESSAGE_SENT_ACTION), PendingIntent.FLAG_ONE_SHOT);
PendingIntent deliveryIntent = PendingIntent.getBroadcast(getContext(), 0,
new Intent(MESSAGE_STATUS_RECEIVED_ACTION), PendingIntent.FLAG_ONE_SHOT);
TelephonyManager telephony = (TelephonyManager)
getContext().getSystemService(Context.TELEPHONY_SERVICE);
// get current phone number
String currentNumber = telephony.getLine1Number();
assertFalse("[RERUN] SIM card does not provide phone number. Use a suitable SIM Card.",
TextUtils.isEmpty(currentNumber));
Log.i(LOG_TAG, String.format("Sending SMS to self: %s", currentNumber));
sendSms(currentNumber, message, sentIntent, deliveryIntent);
}
protected void sendSms(String currentNumber, String text, PendingIntent sentIntent,
PendingIntent deliveryIntent) {
SmsManager.getDefault().sendTextMessage(currentNumber, null, text, sentIntent,
deliveryIntent);
}
/**
* A receiver that tracks if message was sent and received
*/
public class IllegalSmsReceiver extends BroadcastReceiver {
private boolean mIsSmsReceived = false;
private boolean mIsMessageSent = false;
public void onReceive(Context context, Intent intent) {
if (TELEPHONY_SMS_RECEIVED.equals(intent.getAction())) {
// this is bad, received sms without having SMS permission
setSmsReceived();
} else if (MESSAGE_STATUS_RECEIVED_ACTION.equals(intent.getAction())) {
handleResultCode(getResultCode(), "delivery");
} else if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
handleResultCode(getResultCode(), "sent");
} else {
Log.w(LOG_TAG, String.format("unknown intent received: %s", intent.getAction()));
}
}
public boolean isSmsReceived() {
return mIsSmsReceived;
}
private synchronized void setSmsReceived() {
mIsSmsReceived = true;
notify();
}
public boolean isMessageSent() {
return mIsMessageSent;
}
private void handleResultCode(int resultCode, String action) {
if (resultCode == Activity.RESULT_OK) {
Log.i(LOG_TAG, String.format("message %1$s successful", action));
setMessageSentSuccess();
} else {
setMessageSentFailure();
String reason = getErrorReason(resultCode);
Log.e(LOG_TAG, String.format("message %1$s failed: %2$s", action, reason));
}
}
private synchronized void setMessageSentSuccess() {
mIsMessageSent = true;
// set this to true, but don't notify receiver since we don't know if message received
// yet
}
private synchronized void setMessageSentFailure() {
mIsMessageSent = false;
// test environment failure, notify observer so it can stop listening
// TODO: should test retry?
notify();
}
private String getErrorReason(int resultCode) {
switch (resultCode) {
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
return "generic failure";
case SmsManager.RESULT_ERROR_NO_SERVICE:
return "no service";
case SmsManager.RESULT_ERROR_NULL_PDU:
return "null pdu";
case SmsManager.RESULT_ERROR_RADIO_OFF:
return "Radio off";
}
return "unknown";
}
}
public class AppSpecificSmsReceiver extends IllegalSmsReceiver {
private boolean mAppSpecificSmsReceived = false;
@Override
public void onReceive(Context context, Intent intent) {
if (APP_SPECIFIC_SMS_RECEIVED_ACTION.equals(intent.getAction())) {
mAppSpecificSmsReceived = true;
} else {
super.onReceive(context, intent);
}
}
public boolean isAppSpecificSmsReceived() {
return mAppSpecificSmsReceived;
}
}
}