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

Commit ad225205 authored by jiabin's avatar jiabin
Browse files

Add API in RingtoneManager to query if files contain haptic channels.

The query will go to AudioService in case the app itself does not have
the permission to access the files.

Test: test with files (not) containing haptic channels.
Bug: 128012181
Change-Id: I0a3410161e9718197276dc9d6abecada81cf0ee4
parent 6977b323
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -26360,6 +26360,8 @@ package android.media {
    method public android.net.Uri getRingtoneUri(int);
    method public boolean getStopPreviousRingtone();
    method public static android.net.Uri getValidRingtoneUri(android.content.Context);
    method public boolean hasHapticChannels(int);
    method public static boolean hasHapticChannels(@NonNull android.net.Uri);
    method public int inferStreamType();
    method public static boolean isDefault(android.net.Uri);
    method @Nullable public static android.content.res.AssetFileDescriptor openDefaultRingtoneUri(@NonNull android.content.Context, @NonNull android.net.Uri) throws java.io.FileNotFoundException;
+15 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.MediaSessionLegacyHelper;
import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -5441,6 +5442,20 @@ public class AudioManager {
        sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
    }

    /**
     * Return if an asset contains haptic channels or not.
     * @param uri the {@link Uri} of the asset.
     * @return true if the assert contains haptic channels.
     * @hide
     */
    public static boolean hasHapticChannels(Uri uri) {
        try {
            return getService().hasHapticChannels(uri);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    //---------------------------------------------------------
    // Inner classes
    //--------------------
+3 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.media.audiopolicy.AudioProductStrategies;
import android.media.audiopolicy.AudioVolumeGroups;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.projection.IMediaProjection;
import android.net.Uri;

/**
 * {@hide}
@@ -250,6 +251,8 @@ interface IAudioService {

    int removeUidDeviceAffinity(in IAudioPolicyCallback pcb, in int uid);

    boolean hasHapticChannels(in Uri uri);

    // WARNING: read warning at top of file, new methods that need to be used by native
    // code via IAudioManager.h need to be added to the top section.
}
+22 −0
Original line number Diff line number Diff line
@@ -1097,6 +1097,28 @@ public class RingtoneManager {
        return afd;
    }

    /**
     * Returns if the {@link Ringtone} at the given position in the
     * {@link Cursor} contains haptic channels.
     *
     * @param position The position (in the {@link Cursor}) of the ringtone.
     * @return true if the ringtone contains haptic channels.
     */
    public boolean hasHapticChannels(int position) {
        return hasHapticChannels(getRingtoneUri(position));
    }

    /**
     * Returns if the {@link Ringtone} from a given sound URI contains
     * haptic channels or not.
     *
     * @param ringtoneUri The {@link Uri} of a sound or ringtone.
     * @return true if the ringtone contains haptic channels.
     */
    public static boolean hasHapticChannels(@NonNull Uri ringtoneUri) {
        return AudioManager.hasHapticChannels(ringtoneUri);
    }

    /**
     * Creates a {@link android.media.MediaScannerConnection} to scan a ringtone file and add its
     * information to the internal database.
+23 −0
Original line number Diff line number Diff line
@@ -78,6 +78,8 @@ import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IVolumeController;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnErrorListener;
@@ -94,6 +96,7 @@ import android.media.audiopolicy.AudioVolumeGroups;
import android.media.audiopolicy.IAudioPolicyCallback;
import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -4146,6 +4149,26 @@ public class AudioService extends IAudioService.Stub
        }
    }

    /**
     * See AudioManager.hasHapticChannels(Uri).
     */
    public boolean hasHapticChannels(Uri uri) {
        MediaExtractor extractor = new MediaExtractor();
        try {
            extractor.setDataSource(mContext, uri, null);
            for (int i = 0; i < extractor.getTrackCount(); i++) {
                MediaFormat format = extractor.getTrackFormat(i);
                if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
                        && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
                    return true;
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "hasHapticChannels failure:" + e);
        }
        return false;
    }

    ///////////////////////////////////////////////////////////////////////////
    // Inner classes
    ///////////////////////////////////////////////////////////////////////////