Merge "Add telephony commands about SMS apps"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1df3f7f..5a1f2e8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -615,6 +615,8 @@
<protected-broadcast android:name="com.android.server.jobscheduler.FORCE_IDLE" />
<protected-broadcast android:name="com.android.server.jobscheduler.UNFORCE_IDLE" />
+ <protected-broadcast android:name="android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -4136,6 +4138,12 @@
<permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS"
android:protectionLevel="signature" />
+ <!-- @hide Permission that protects the
+ {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
+ broadcast -->
+ <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
+ android:protectionLevel="signature" />
+
<application android:process="system"
android:persistent="true"
android:hasCode="false"
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 722df67..4846092 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -1233,6 +1233,17 @@
"android.provider.action.EXTERNAL_PROVIDER_CHANGE";
/**
+ * Same as {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} but it's implicit (e.g. sent to
+ * all apps) and requires
+ * {@link android.Manifest.permission#MONITOR_DEFAULT_SMS_PACKAGE} to receive.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL =
+ "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL";
+
+ /**
* Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
* {@link #DATA_SMS_RECEIVED_ACTION} intent.
*
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index afb1d82..e1c770c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1587,4 +1587,19 @@
* Return the network selection mode on the subscription with id {@code subId}.
*/
int getNetworkSelectionMode(int subId);
+
+ /**
+ * Get a list of SMS apps on a user.
+ */
+ String[] getSmsApps(int userId);
+
+ /**
+ * Get the default SMS app on a given user.
+ */
+ String getDefaultSmsApp(int userId);
+
+ /**
+ * Set the default SMS app to a given package on a given user.
+ */
+ void setDefaultSmsApp(int userId, String packageName);
}
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index d8ef429..39722c6 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -209,7 +209,14 @@
* Support smsto Uri scheme.
*/
public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
- int userId = getIncomingUserId(context);
+ return getApplicationCollectionAsUser(context, getIncomingUserId(context));
+ }
+
+ /**
+ * Same as {@link #getApplicationCollection} but it takes a target user ID.
+ */
+ public static Collection<SmsApplicationData> getApplicationCollectionAsUser(Context context,
+ int userId) {
final long token = Binder.clearCallingIdentity();
try {
return getApplicationCollectionInternal(context, userId);
@@ -535,13 +542,20 @@
* needs to have permission to set AppOps and write to secure settings.
*/
public static void setDefaultApplication(String packageName, Context context) {
+ setDefaultApplicationAsUser(packageName, context, getIncomingUserId(context));
+ }
+
+ /**
+ * Same as {@link #setDefaultApplication} but takes a target user id.
+ */
+ public static void setDefaultApplicationAsUser(String packageName, Context context,
+ int userId) {
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
if (!tm.isSmsCapable()) {
// No phone, no SMS
return;
}
- final int userId = getIncomingUserId(context);
final long token = Binder.clearCallingIdentity();
try {
setDefaultApplicationInternal(packageName, context, userId);
@@ -552,6 +566,8 @@
private static void setDefaultApplicationInternal(String packageName, Context context,
int userId) {
+ final UserHandle userHandle = UserHandle.of(userId);
+
// Get old package name
String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
@@ -628,7 +644,7 @@
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
}
- context.sendBroadcast(oldAppIntent);
+ context.sendBroadcastAsUser(oldAppIntent, userHandle);
}
// Notify the new sms app that it's now the default (if the new sms app has a receiver
// to handle the changed default sms intent).
@@ -646,8 +662,16 @@
if (DEBUG_MULTIUSER) {
Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
}
- context.sendBroadcast(intent);
+ context.sendBroadcastAsUser(intent, userHandle);
}
+
+ // Send an implicit broadcast for the system server.
+ // (or anyone with MONITOR_DEFAULT_SMS_PACKAGE, really.)
+ final Intent intent =
+ new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+ context.sendBroadcastAsUser(intent, userHandle,
+ permission.MONITOR_DEFAULT_SMS_PACKAGE);
+
MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
applicationData.mPackageName);
}
@@ -799,7 +823,18 @@
* @return component name of the app and class to deliver SMS messages to
*/
public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
+ return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId(context));
+ }
+
+ /**
+ * Gets the default SMS application on a given user
+ * @param context context from the calling app
+ * @param updateIfNeeded update the default app if there is no valid default app configured.
+ * @param userId target user ID.
+ * @return component name of the app and class to deliver SMS messages to
+ */
+ public static ComponentName getDefaultSmsApplicationAsUser(Context context,
+ boolean updateIfNeeded, int userId) {
final long token = Binder.clearCallingIdentity();
try {
ComponentName component = null;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 06378ba..23ea237 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -21,6 +21,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.os.Binder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.Rlog;
@@ -307,4 +308,17 @@
Rlog.e(LOG_TAG, "Phone process is down, cannot check carrier privileges");
return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
}
+
+ /**
+ * Throws if the caller is not of a shell (or root) UID.
+ *
+ * @param callingUid pass Binder.callingUid().
+ */
+ public static void enforceShellOnly(int callingUid, String message) {
+ if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ return; // okay
+ }
+
+ throw new SecurityException(message + ": Only shell user can call it");
+ }
}