DevicePolicy API to set default dialer and SMS app

* Add new API to allow DO and COPE PO to set default dialer app.
* Open up existing setDefaultSmsApplication() API to COPE PO so
  it can use it to set default SMS app in the profile.

Bug: 268472989
Test: DefaultSmsApplicationTest
      DefaultDialerApplicationTest
Change-Id: Iff94f57250d3a5837faa542aae0fd12de0b85572
This commit is contained in:
Rubin Xu
2023-02-09 14:03:50 +00:00
parent 86e5851229
commit c6507df716
5 changed files with 129 additions and 3 deletions

View File

@@ -7832,6 +7832,7 @@ package android.app.admin {
method @Deprecated public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
method @Deprecated public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
method public void setCrossProfilePackages(@NonNull android.content.ComponentName, @NonNull java.util.Set<java.lang.String>);
method public void setDefaultDialerApplication(@NonNull String);
method public void setDefaultSmsApplication(@NonNull android.content.ComponentName, @NonNull String);
method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);

View File

@@ -9730,6 +9730,11 @@ public class DevicePolicyManager {
* of an organization-owned managed profile and the package must be a pre-installed system
* package. If called on the parent instance, then the default SMS application is set on the
* personal profile.
* <p>
* Starting from Android {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, the profile
* owner of an organization-owned managed profile can also call this method directly (not on the
* parent profile instance) to set the default SMS application in the work profile. This is only
* meaningful when work profile telephony is enabled by {@link #setManagedSubscriptionsPolicy}.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The name of the package to set as the default SMS application.
@@ -9750,6 +9755,36 @@ public class DevicePolicyManager {
}
}
/**
* Must be called by a device owner or a profile owner of an organization-owned managed profile
* to set the default dialer application for the calling user.
* <p>
* When the profile owner of an organization-owned managed profile calls this method, it sets
* the default dialer application in the work profile. This is only meaningful when work profile
* telephony is enabled by {@link #setManagedSubscriptionsPolicy}.
* <p>
* If the device does not support telephony ({@link PackageManager#FEATURE_TELEPHONY}), calling
* this method will do nothing.
*
* @param packageName The name of the package to set as the default dialer application.
* @throws SecurityException if {@code admin} is not a device or profile owner or a
* profile owner of an organization-owned managed profile.
* @throws IllegalArgumentException if the package cannot be set as the default dialer, for
* example if the package is not installed or does not expose
* the expected activities or services that a dialer app is
* required to have.
*/
public void setDefaultDialerApplication(@NonNull String packageName) {
throwIfParentInstance("setDefaultDialerApplication");
if (mService != null) {
try {
mService.setDefaultDialerApplication(packageName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
/**
* Called by a profile owner or device owner to grant permission to a package to manage
* application restrictions for the calling user via {@link #setApplicationRestrictions} and

View File

@@ -237,6 +237,7 @@ interface IDevicePolicyManager {
void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName);
void setDefaultSmsApplication(in ComponentName admin, String packageName, boolean parent);
void setDefaultDialerApplication(String packageName);
void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings);
Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName);

View File

@@ -175,6 +175,8 @@ class ActiveAdmin {
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
private static final String ATTR_PACKAGE_POLICY_MODE = "package-policy-type";
private static final String TAG_CREDENTIAL_MANAGER_POLICY = "credential-manager-policy";
private static final String TAG_DIALER_PACKAGE = "dialer_package";
private static final String TAG_SMS_PACKAGE = "sms_package";
DeviceAdminInfo info;
@@ -349,6 +351,8 @@ class ActiveAdmin {
boolean mUsbDataSignalingEnabled = USB_DATA_SIGNALING_ENABLED_DEFAULT;
int mWifiMinimumSecurityLevel = DevicePolicyManager.WIFI_SECURITY_OPEN;
String mDialerPackage;
String mSmsPackage;
ActiveAdmin(DeviceAdminInfo info, boolean isParent) {
this.info = info;
@@ -658,6 +662,12 @@ class ActiveAdmin {
mManagedSubscriptionsPolicy.saveToXml(out);
out.endTag(null, TAG_MANAGED_SUBSCRIPTIONS_POLICY);
}
if (!TextUtils.isEmpty(mDialerPackage)) {
writeAttributeValueToXml(out, TAG_DIALER_PACKAGE, mDialerPackage);
}
if (!TextUtils.isEmpty(mSmsPackage)) {
writeAttributeValueToXml(out, TAG_SMS_PACKAGE, mSmsPackage);
}
}
private void writePackagePolicy(TypedXmlSerializer out, String tag,
@@ -966,6 +976,10 @@ class ActiveAdmin {
mManagedSubscriptionsPolicy = ManagedSubscriptionsPolicy.readFromXml(parser);
} else if (TAG_CREDENTIAL_MANAGER_POLICY.equals(tag)) {
mCredentialManagerPolicy = readPackagePolicy(parser);
} else if (TAG_DIALER_PACKAGE.equals(tag)) {
mDialerPackage = parser.getAttributeValue(null, ATTR_VALUE);
} else if (TAG_SMS_PACKAGE.equals(tag)) {
mSmsPackage = parser.getAttributeValue(null, ATTR_VALUE);
} else {
Slogf.w(LOG_TAG, "Unknown admin tag: %s", tag);
XmlUtils.skipCurrentTag(parser);
@@ -1444,5 +1458,10 @@ class ActiveAdmin {
pw.println(mManagedSubscriptionsPolicy);
pw.decreaseIndent();
}
pw.print("mDialerPackage=");
pw.println(mDialerPackage);
pw.print("mSmsPackage=");
pw.println(mSmsPackage);
}
}

View File

@@ -313,6 +313,7 @@ import android.net.Uri;
import android.net.VpnManager;
import android.net.metrics.IpConnectivityLog;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -453,8 +454,12 @@ import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -807,6 +812,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final UserManagerInternal mUserManagerInternal;
final UsageStatsManagerInternal mUsageStatsManagerInternal;
final TelephonyManager mTelephonyManager;
final RoleManager mRoleManager;
private final LockPatternUtils mLockPatternUtils;
private final LockSettingsInternal mLockSettingsInternal;
private final DeviceAdminServiceController mDeviceAdminServiceController;
@@ -1593,6 +1599,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return mContext.getSystemService(TelephonyManager.class);
}
RoleManager getRoleManager() {
return mContext.getSystemService(RoleManager.class);
}
TrustManager getTrustManager() {
return (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
}
@@ -1935,6 +1945,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mIPackageManager = Objects.requireNonNull(injector.getIPackageManager());
mIPermissionManager = Objects.requireNonNull(injector.getIPermissionManager());
mTelephonyManager = Objects.requireNonNull(injector.getTelephonyManager());
mRoleManager = Objects.requireNonNull(injector.getRoleManager());
mLocalService = new LocalService();
mLockPatternUtils = injector.newLockPatternUtils();
@@ -10488,14 +10499,73 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final CallerIdentity caller = getCallerIdentity(admin);
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
|| (parent && isProfileOwnerOfOrganizationOwnedDevice(caller)));
|| isProfileOwnerOfOrganizationOwnedDevice(caller));
final int userId;
if (parent) {
userId = getProfileParentId(mInjector.userHandleGetCallingUserId());
mInjector.binderWithCleanCallingIdentity(() -> enforcePackageIsSystemPackage(
packageName, getProfileParentId(mInjector.userHandleGetCallingUserId())));
packageName, userId));
} else {
userId = mInjector.userHandleGetCallingUserId();
}
mInjector.binderWithCleanCallingIdentity(() ->
SmsApplication.setDefaultApplication(packageName, mContext));
SmsApplication.setDefaultApplicationAsUser(packageName, mContext, userId));
synchronized (getLockObject()) {
final ActiveAdmin activeAdmin = getParentOfAdminIfRequired(
getProfileOwnerOrDeviceOwnerLocked(caller.getUserId()), parent);
if (!Objects.equals(activeAdmin.mSmsPackage, packageName)) {
activeAdmin.mSmsPackage = packageName;
saveSettingsLocked(caller.getUserId());
}
}
}
@Override
public void setDefaultDialerApplication(String packageName) {
if (!mHasFeature || !mHasTelephonyFeature) {
return;
}
final CallerIdentity caller = getCallerIdentity();
final int callerUserId = caller.getUserId();
Preconditions.checkCallAuthorization(isDefaultDeviceOwner(caller)
|| isProfileOwnerOfOrganizationOwnedDevice(caller));
mInjector.binderWithCleanCallingIdentity(() -> {
CompletableFuture<Void> future = new CompletableFuture<>();
Consumer<Boolean> callback = successful -> {
if (successful) {
future.complete(null);
} else {
future.completeExceptionally(new IllegalArgumentException(
packageName + " cannot be set as the dialer"));
}
};
mRoleManager.addRoleHolderAsUser(
RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(callerUserId),
AsyncTask.THREAD_POOL_EXECUTOR, callback);
try {
future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
throw new IllegalArgumentException("Timeout when setting the app as the dialer", e);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof IllegalArgumentException) {
throw (IllegalArgumentException) cause;
} else {
throw new IllegalStateException(cause);
}
}
});
// Only save the package when the setting the role succeeded without exception.
synchronized (getLockObject()) {
final ActiveAdmin admin = getProfileOwnerOrDeviceOwnerLocked(callerUserId);
if (!Objects.equals(admin.mDialerPackage, packageName)) {
admin.mDialerPackage = packageName;
saveSettingsLocked(callerUserId);
}
}
}
@Override