Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6507df7 authored by Rubin Xu's avatar Rubin Xu
Browse files

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
parent 86e58512
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+35 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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);
+19 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+73 −3
Original line number Diff line number Diff line
@@ -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