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

Commit ea324d38 authored by Olivier Nshimiye's avatar Olivier Nshimiye Committed by Android (Google) Code Review
Browse files

Merge changes from topic "generic-profile-availability-intents" into main

* changes:
  Broadcast generic profile availability intents
  Add generic broadcasts for profile availability.
parents 33e5b16c 9ec9eb24
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11002,8 +11002,10 @@ package android.content {
    field public static final String ACTION_PROCESS_TEXT = "android.intent.action.PROCESS_TEXT";
    field public static final String ACTION_PROFILE_ACCESSIBLE = "android.intent.action.PROFILE_ACCESSIBLE";
    field public static final String ACTION_PROFILE_ADDED = "android.intent.action.PROFILE_ADDED";
    field @FlaggedApi("android.os.allow_private_profile") public static final String ACTION_PROFILE_AVAILABLE = "android.intent.action.PROFILE_AVAILABLE";
    field public static final String ACTION_PROFILE_INACCESSIBLE = "android.intent.action.PROFILE_INACCESSIBLE";
    field public static final String ACTION_PROFILE_REMOVED = "android.intent.action.PROFILE_REMOVED";
    field @FlaggedApi("android.os.allow_private_profile") public static final String ACTION_PROFILE_UNAVAILABLE = "android.intent.action.PROFILE_UNAVAILABLE";
    field public static final String ACTION_PROVIDER_CHANGED = "android.intent.action.PROVIDER_CHANGED";
    field public static final String ACTION_QUICK_CLOCK = "android.intent.action.QUICK_CLOCK";
    field public static final String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
+30 −0
Original line number Diff line number Diff line
@@ -18,11 +18,13 @@ package android.content;
import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
import static android.content.ContentProvider.maybeAddUserId;
import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE;
import android.Manifest;
import android.accessibilityservice.AccessibilityService;
import android.annotation.AnyRes;
import android.annotation.BroadcastBehavior;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -4156,6 +4158,34 @@ public class Intent implements Parcelable, Cloneable {
    public static final String ACTION_MANAGED_PROFILE_UNAVAILABLE =
            "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
    /**
     * Broadcast sent to the primary user when an associated profile has become available.
     * This is sent when a user disables quiet mode for the profile. Carries an extra
     * {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile. When quiet mode is
     * changed, this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the
     * new state of quiet mode. This is only sent to registered receivers, not manifest receivers.
     *
     * <p>This broadcast is similar to {@link #ACTION_MANAGED_PROFILE_AVAILABLE} but functions as a
     * generic broadcast for all users of type {@link android.content.pm.UserInfo#isProfile()}}.
     */
    @FlaggedApi(FLAG_ALLOW_PRIVATE_PROFILE)
    public static final String ACTION_PROFILE_AVAILABLE =
            "android.intent.action.PROFILE_AVAILABLE";
    /**
     * Broadcast sent to the primary user when an associated profile has become unavailable.
     * This is sent when a user enables quiet mode for the profile. Carries an extra
     * {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile. When quiet mode is
     * changed, this broadcast will carry a boolean extra {@link #EXTRA_QUIET_MODE} indicating the
     * new state of quiet mode. This is only sent to registered receivers, not manifest receivers.
     *
     * <p>This broadcast is similar to {@link #ACTION_MANAGED_PROFILE_UNAVAILABLE} but functions as
     * a generic broadcast for all users of type {@link android.content.pm.UserInfo#isProfile()}}.
     */
    @FlaggedApi(FLAG_ALLOW_PRIVATE_PROFILE)
    public static final String ACTION_PROFILE_UNAVAILABLE =
            "android.intent.action.PROFILE_UNAVAILABLE";
    /**
     * Broadcast sent to the parent user when an associated profile has been started and unlocked.
     * Carries an extra {@link #EXTRA_USER} that specifies the {@link UserHandle} of the profile.
+4 −0
Original line number Diff line number Diff line
@@ -828,6 +828,10 @@
    <protected-broadcast android:name="android.app.admin.action.DEVICE_POLICY_SET_RESULT" />
    <protected-broadcast android:name="android.app.admin.action.DEVICE_POLICY_CHANGED" />

    <!-- Added in V -->
    <protected-broadcast android:name="android.intent.action.PROFILE_AVAILABLE" />
    <protected-broadcast android:name="android.intent.action.PROFILE_UNAVAILABLE" />

    <!-- ====================================================================== -->
    <!--                          RUNTIME PERMISSIONS                           -->
    <!-- ====================================================================== -->
+50 −20
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Flags;
import android.os.Handler;
import android.os.IBinder;
import android.os.IProgressListener;
@@ -1332,29 +1333,49 @@ public class UserManagerService extends IUserManager.Stub {
                && user.profileGroupId == profile.profileGroupId);
    }

    private void broadcastProfileAvailabilityChanges(UserHandle profileHandle,
            UserHandle parentHandle, boolean inQuietMode) {
    private Intent buildProfileAvailabilityIntent(UserInfo profile, boolean enableQuietMode,
            boolean useManagedActions) {
        Intent intent = new Intent();
        if (inQuietMode) {
            intent.setAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
        } else {
            intent.setAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
        }
        intent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
        intent.putExtra(Intent.EXTRA_USER, profileHandle);
        intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
        intent.setAction(getAvailabilityIntentAction(enableQuietMode, useManagedActions));
        intent.putExtra(Intent.EXTRA_QUIET_MODE, enableQuietMode);
        intent.putExtra(Intent.EXTRA_USER, profile.getUserHandle());
        intent.putExtra(Intent.EXTRA_USER_HANDLE, profile.getUserHandle().getIdentifier());
        intent.addFlags(
                Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
        return intent;
    }

    private String getAvailabilityIntentAction(boolean enableQuietMode, boolean useManagedActions) {
        return useManagedActions ?
                enableQuietMode ?
                        Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE
                        : Intent.ACTION_MANAGED_PROFILE_AVAILABLE
                : enableQuietMode ?
                        Intent.ACTION_PROFILE_UNAVAILABLE
                        : Intent.ACTION_PROFILE_AVAILABLE;
    }

    private void broadcastProfileAvailabilityChanges(UserInfo profileInfo,
            UserHandle parentHandle, boolean enableQuietMode, boolean useManagedActions) {
        Intent availabilityIntent = buildProfileAvailabilityIntent(profileInfo, enableQuietMode,
                useManagedActions);
        if (profileInfo.isManagedProfile()) {
            getDevicePolicyManagerInternal().broadcastIntentToManifestReceivers(
                intent, parentHandle, /* requiresPermission= */ true);
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
                    availabilityIntent, parentHandle, /* requiresPermission= */ true);
        }
        // TODO(b/302708423): Restrict the apps that can receive these intents in case of a private
        //  profile.
        final Bundle options = new BroadcastOptions()
                .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE)
                .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
                // Both actions use single namespace because only the final state matters.
                .setDeliveryGroupMatchingKey(
                        Intent.ACTION_MANAGED_PROFILE_AVAILABLE /* namespace */,
                        String.valueOf(profileHandle.getIdentifier()) /* key */)
                        useManagedActions ? Intent.ACTION_MANAGED_PROFILE_AVAILABLE
                                : Intent.ACTION_PROFILE_AVAILABLE,
                        String.valueOf(profileInfo.getUserHandle().getIdentifier()) /* key */)
                .toBundle();
        mContext.sendBroadcastAsUser(intent, parentHandle, /* receiverPermission= */ null, options);
        mContext.sendBroadcastAsUser(availabilityIntent, parentHandle, /* receiverPermission= */
                null, options);
    }

    @Override
@@ -1481,7 +1502,7 @@ public class UserManagerService extends IUserManager.Stub {
            profile = getUserInfoLU(userId);
            parent = getProfileParentLU(userId);

            if (profile == null || !profile.isManagedProfile()) {
            if (profile == null || !profile.isProfile()) {
                throw new IllegalArgumentException("User " + userId + " is not a profile");
            }
            if (profile.isQuietModeEnabled() == enableQuietMode) {
@@ -1534,8 +1555,17 @@ public class UserManagerService extends IUserManager.Stub {
        }

        logQuietModeEnabled(userId, enableQuietMode, callingPackage);
        broadcastProfileAvailabilityChanges(profile.getUserHandle(), parent.getUserHandle(),
                enableQuietMode);

        // Broadcast generic intents for all profiles
        if (Flags.allowPrivateProfile()) {
            broadcastProfileAvailabilityChanges(profile, parent.getUserHandle(),
                    enableQuietMode, false);
        }
        // Broadcast Managed profile availability intents too for managed profiles.
        if (profile.isManagedProfile()){
            broadcastProfileAvailabilityChanges(profile, parent.getUserHandle(),
                     enableQuietMode, true);
        }
    }

    private void setAppOpsRestrictedForQuietMode(@UserIdInt int userId, boolean restrict) {
@@ -1582,7 +1612,7 @@ public class UserManagerService extends IUserManager.Stub {
            synchronized (mUsersLock) {
                info = getUserInfoLU(userId);
            }
            if (info == null || !info.isManagedProfile()) {
            if (info == null || !info.isProfile()) {
                return false;
            }
            return info.isQuietModeEnabled();