diff options
6 files changed, 139 insertions, 20 deletions
| diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java index 8deb0c4451ea..e9e144c43081 100644 --- a/media/java/android/media/RingtoneManager.java +++ b/media/java/android/media/RingtoneManager.java @@ -795,10 +795,10 @@ public class RingtoneManager {          return ringtoneUri;      } -     +      /**       * Sets the {@link Uri} of the default sound for a given sound type. -     *  +     *       * @param context A context used for querying.       * @param type The type whose default sound should be set. One of       *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or @@ -819,6 +819,21 @@ public class RingtoneManager {          if(!isInternalRingtoneUri(ringtoneUri)) {              ringtoneUri = ContentProvider.maybeAddUserId(ringtoneUri, context.getUserId());          } + +        if (ringtoneUri != null) { +            final String mimeType = resolver.getType(ringtoneUri); +            if (mimeType == null) { +                Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri +                        + " ignored: failure to find mimeType (no access from this context?)"); +                return; +            } +            if (!(mimeType.startsWith("audio/") || mimeType.equals("application/ogg"))) { +                Log.e(TAG, "setActualDefaultRingtoneUri for URI:" + ringtoneUri +                        + " ignored: associated mimeType:" + mimeType + " is not an audio type"); +                return; +            } +        } +          Settings.System.putStringForUser(resolver, setting,                  ringtoneUri != null ? ringtoneUri.toString() : null, context.getUserId()); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 4199f9c77b80..a6300f033a36 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -978,9 +978,9 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {          final ContentResolver cr = mContext.getContentResolver();          // From SecuritySettings -        final long lockAfterTimeout = Settings.Secure.getInt(cr, +        final long lockAfterTimeout = Settings.Secure.getIntForUser(cr,                  Settings.Secure.LOCK_SCREEN_LOCK_AFTER_TIMEOUT, -                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT); +                KEYGUARD_LOCK_AFTER_DELAY_DEFAULT, userId);          // From DevicePolicyAdmin          final long policyTimeout = mLockPatternUtils.getDevicePolicyManager() @@ -992,8 +992,8 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {              timeout = lockAfterTimeout;          } else {              // From DisplaySettings -            long displayTimeout = Settings.System.getInt(cr, SCREEN_OFF_TIMEOUT, -                    KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT); +            long displayTimeout = Settings.System.getIntForUser(cr, SCREEN_OFF_TIMEOUT, +                    KEYGUARD_DISPLAY_TIMEOUT_DELAY_DEFAULT, userId);              // policy in effect. Make sure we don't go beyond policy limit.              displayTimeout = Math.max(displayTimeout, 0); // ignore negative values @@ -1813,7 +1813,10 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {      private void playSound(int soundId) {          if (soundId == 0) return;          final ContentResolver cr = mContext.getContentResolver(); -        if (Settings.System.getInt(cr, Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1) == 1) { +        int lockscreenSoundsEnabled = Settings.System.getIntForUser(cr, +                Settings.System.LOCKSCREEN_SOUNDS_ENABLED, 1, +                KeyguardUpdateMonitor.getCurrentUser()); +        if (lockscreenSoundsEnabled == 1) {              mLockSounds.stop(mLockSoundStreamId);              // Init mAudioManager diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 02b7582a8637..445195a23801 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -18,6 +18,8 @@ package com.android.server.media;  import android.annotation.Nullable;  import android.app.PendingIntent; +import android.content.ContentProvider; +import android.content.ContentResolver;  import android.content.Context;  import android.content.Intent;  import android.content.pm.ParceledListSlice; @@ -49,11 +51,13 @@ import android.os.Process;  import android.os.RemoteException;  import android.os.ResultReceiver;  import android.os.SystemClock; +import android.text.TextUtils;  import android.util.Log;  import android.util.Slog;  import android.view.KeyEvent;  import com.android.server.LocalServices; +import com.android.server.uri.UriGrantsManagerInternal;  import java.io.PrintWriter;  import java.util.ArrayList; @@ -67,6 +71,10 @@ import java.util.List;  // TODO(jaewan): Do not call service method directly -- introduce listener instead.  public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionRecordImpl {      private static final String TAG = "MediaSessionRecord"; +    private static final String[] ART_URIS = new String[] { +            MediaMetadata.METADATA_KEY_ALBUM_ART_URI, +            MediaMetadata.METADATA_KEY_ART_URI, +            MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI};      private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);      /** @@ -120,6 +128,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR      private final SessionStub mSession;      private final SessionCb mSessionCb;      private final MediaSessionService mService; +    private final UriGrantsManagerInternal mUgmInternal;      private final Context mContext;      private final Object mLock = new Object(); @@ -182,6 +191,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR          mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);          mAudioAttrs = DEFAULT_ATTRIBUTES;          mPolicies = policies; +        mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class);          // May throw RemoteException if the session app is killed.          mSessionCb.mCb.asBinder().linkToDeath(this, 0); @@ -859,21 +869,45 @@ public class MediaSessionRecord implements IBinder.DeathRecipient, MediaSessionR          public void setMetadata(MediaMetadata metadata, long duration, String metadataDescription)                  throws RemoteException {              synchronized (mLock) { -                MediaMetadata temp = metadata == null ? null : new MediaMetadata.Builder(metadata) -                        .build(); -                // This is to guarantee that the underlying bundle is unparceled -                // before we set it to prevent concurrent reads from throwing an -                // exception -                if (temp != null) { -                    temp.size(); -                } -                mMetadata = temp;                  mDuration = duration;                  mMetadataDescription = metadataDescription; +                mMetadata = sanitizeMediaMetadata(metadata);              }              mHandler.post(MessageHandler.MSG_UPDATE_METADATA);          } +        private MediaMetadata sanitizeMediaMetadata(MediaMetadata metadata) { +            if (metadata == null) { +                return null; +            } +            MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder(metadata); +            for (String key: ART_URIS) { +                String uriString = metadata.getString(key); +                if (TextUtils.isEmpty(uriString)) { +                    continue; +                } +                Uri uri = Uri.parse(uriString); +                if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { +                    continue; +                } +                try { +                    mUgmInternal.checkGrantUriPermission(getUid(), +                            getPackageName(), +                            ContentProvider.getUriWithoutUserId(uri), +                            Intent.FLAG_GRANT_READ_URI_PERMISSION, +                            ContentProvider.getUserIdFromUri(uri, getUserId())); +                } catch (SecurityException e) { +                    metadataBuilder.putString(key, null); +                } +            } +            MediaMetadata sanitizedMetadata = metadataBuilder.build(); +            // sanitizedMetadata.size() guarantees that the underlying bundle is unparceled +            // before we set it to prevent concurrent reads from throwing an +            // exception +            sanitizedMetadata.size(); +            return sanitizedMetadata; +        } +          @Override          public void setPlaybackState(PlaybackState state) throws RemoteException {              int oldState = mPlaybackState == null diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java index 1f8aafbca476..77034041f1fd 100644 --- a/telecomm/java/android/telecom/ParcelableConference.java +++ b/telecomm/java/android/telecom/ParcelableConference.java @@ -21,12 +21,12 @@ import android.os.Bundle;  import android.os.Parcel;  import android.os.Parcelable; +import com.android.internal.telecom.IVideoProvider; +  import java.util.ArrayList;  import java.util.Collections;  import java.util.List; -import com.android.internal.telecom.IVideoProvider; -  /**   * A parcelable representation of a conference connection.   * @hide @@ -287,6 +287,14 @@ public final class ParcelableConference implements Parcelable {          return mCallDirection;      } +    public String getCallerDisplayName() { +        return mCallerDisplayName; +    } + +    public int getCallerDisplayNamePresentation() { +        return mCallerDisplayNamePresentation; +    } +      public static final @android.annotation.NonNull Parcelable.Creator<ParcelableConference> CREATOR =              new Parcelable.Creator<ParcelableConference> () {          @Override diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java index 762c93a49022..b7346331dc60 100644 --- a/telecomm/java/android/telecom/StatusHints.java +++ b/telecomm/java/android/telecom/StatusHints.java @@ -16,14 +16,19 @@  package android.telecom; +import android.annotation.Nullable;  import android.annotation.SystemApi;  import android.content.ComponentName;  import android.content.Context;  import android.graphics.drawable.Drawable;  import android.graphics.drawable.Icon; +import android.os.Binder;  import android.os.Bundle;  import android.os.Parcel;  import android.os.Parcelable; +import android.os.UserHandle; + +import com.android.internal.annotations.VisibleForTesting;  import java.util.Objects; @@ -33,7 +38,7 @@ import java.util.Objects;  public final class StatusHints implements Parcelable {      private final CharSequence mLabel; -    private final Icon mIcon; +    private Icon mIcon;      private final Bundle mExtras;      /** @@ -48,11 +53,31 @@ public final class StatusHints implements Parcelable {      public StatusHints(CharSequence label, Icon icon, Bundle extras) {          mLabel = label; -        mIcon = icon; +        mIcon = validateAccountIconUserBoundary(icon, Binder.getCallingUserHandle());          mExtras = extras;      }      /** +     * @param icon +     * @hide +     */ +    @VisibleForTesting +    public StatusHints(@Nullable Icon icon) { +        mLabel = null; +        mExtras = null; +        mIcon = icon; +    } + +    /** +     * +     * @param icon +     * @hide +     */ +    public void setIcon(@Nullable Icon icon) { +        mIcon = icon; +    } + +    /**       * @return A package used to load the icon.       *       * @hide @@ -112,6 +137,30 @@ public final class StatusHints implements Parcelable {          return 0;      } +    /** +     * Validates the StatusHints image icon to see if it's not in the calling user space. +     * Invalidates the icon if so, otherwise returns back the original icon. +     * +     * @param icon +     * @return icon (validated) +     * @hide +     */ +    public static Icon validateAccountIconUserBoundary(Icon icon, UserHandle callingUserHandle) { +        // Refer to Icon#getUriString for context. The URI string is invalid for icons of +        // incompatible types. +        if (icon != null && (icon.getType() == Icon.TYPE_URI +                || icon.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP)) { +            String encodedUser = icon.getUri().getEncodedUserInfo(); +            // If there is no encoded user, the URI is calling into the calling user space +            if (encodedUser != null) { +                int userId = Integer.parseInt(encodedUser); +                // Do not try to save the icon if the user id isn't in the calling user space. +                if (userId != callingUserHandle.getIdentifier()) return null; +            } +        } +        return icon; +    } +      @Override      public void writeToParcel(Parcel out, int flags) {          out.writeCharSequence(mLabel); diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java index 8222eef51024..db7506663a0d 100644 --- a/telephony/java/android/telephony/SubscriptionInfo.java +++ b/telephony/java/android/telephony/SubscriptionInfo.java @@ -16,6 +16,7 @@  package android.telephony; +import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.SystemApi;  import android.compat.annotation.UnsupportedAppUsage; @@ -694,6 +695,15 @@ public class SubscriptionInfo implements Parcelable {      }      /** +     * @hide +     * @return mCarrierConfigAccessRules associated with this subscription. +     */ +    public @NonNull List<UiccAccessRule> getCarrierConfigAccessRules() { +        return mCarrierConfigAccessRules == null ? Collections.emptyList() : +            Arrays.asList(mCarrierConfigAccessRules); +    } + +    /**       * Returns the card string of the SIM card which contains the subscription.       *       * Starting with API level 30, returns the card string if the calling app has been granted the |