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

Commit 96f794f4 authored by Shubang Lu's avatar Shubang Lu
Browse files

[MQ] Handle active profile listener

Test: CTS
Bug: 405477207
Flag: android.media.tv.flags.media_quality_fw
Change-Id: I0ae8fccdd0ddc41ac671d462e5bc221c973d400b
parent 256ba236
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -31,16 +31,26 @@ import androidx.annotation.NonNull;
public final class ActiveProcessingPicture implements Parcelable {
    private final int mId;
    private final String mProfileId;
    private final boolean mForGlobal;

    public ActiveProcessingPicture(int id, @NonNull String profileId) {
        mId = id;
        mProfileId = profileId;
        mForGlobal = true;
    }

    /** @hide */
    public ActiveProcessingPicture(int id, @NonNull String profileId, boolean forGlobal) {
        mId = id;
        mProfileId = profileId;
        mForGlobal = forGlobal;
    }

    /** @hide */
    ActiveProcessingPicture(Parcel in) {
        mId = in.readInt();
        mProfileId = in.readString();
        mForGlobal = in.readBoolean();
    }

    @NonNull
@@ -73,6 +83,14 @@ public final class ActiveProcessingPicture implements Parcelable {
        return mProfileId;
    }

    /**
     * @hide
     */
    @NonNull
    public boolean isForGlobal() {
        return mForGlobal;
    }

    @Override
    public int describeContents() {
        return 0;
@@ -82,5 +100,6 @@ public final class ActiveProcessingPicture implements Parcelable {
    public void writeToParcel(@NonNull Parcel dest, int flags) {
        dest.writeInt(mId);
        dest.writeString(mProfileId);
        dest.writeBoolean(mForGlobal);
    }
}
+29 −0
Original line number Diff line number Diff line
@@ -214,11 +214,31 @@ public final class MediaQualityManager {
            }
        };

        IActiveProcessingPictureListener apListener = new IActiveProcessingPictureListener.Stub() {
            @Override
            public void onActiveProcessingPicturesChanged(List<ActiveProcessingPicture> aps) {
                List<ActiveProcessingPicture> nonGlobal = new ArrayList<>();
                for (ActiveProcessingPicture ap : aps) {
                    if (!ap.isForGlobal()) {
                        nonGlobal.add(ap);
                    }
                }
                for (ActiveProcessingPictureListenerRecord record : mApListenerRecords) {
                    if (record.mIsGlobal) {
                        record.postActiveProcessingPicturesChanged(aps);
                    } else {
                        record.postActiveProcessingPicturesChanged(nonGlobal);
                    }
                }
            }
        };

        try {
            if (mService != null) {
                mService.registerPictureProfileCallback(ppCallback);
                mService.registerSoundProfileCallback(spCallback);
                mService.registerAmbientBacklightCallback(abCallback);
                mService.registerActiveProcessingPictureListener(apListener);
            }
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
@@ -1225,6 +1245,15 @@ public final class MediaQualityManager {
        public Consumer<List<ActiveProcessingPicture>> getListener() {
            return mListener;
        }

        public void postActiveProcessingPicturesChanged(List<ActiveProcessingPicture> aps) {
            mExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    mListener.accept(aps);
                }
            });
        }
    }

    /**
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.media.quality;

import android.media.quality.ActiveProcessingPicture;

/**
 * Interface to receive event from media quality service.
 * @hide
 */
oneway interface IActiveProcessingPictureListener {
    void onActiveProcessingPicturesChanged(in List<ActiveProcessingPicture> ap);
}
+2 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.media.quality;

import android.media.quality.AmbientBacklightSettings;
import android.media.quality.IActiveProcessingPictureListener;
import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IPictureProfileCallback;
import android.media.quality.ISoundProfileCallback;
@@ -70,6 +71,7 @@ interface IMediaQualityManager {
    void registerPictureProfileCallback(in IPictureProfileCallback cb);
    void registerSoundProfileCallback(in ISoundProfileCallback cb);
    void registerAmbientBacklightCallback(in IAmbientBacklightCallback cb);
    void registerActiveProcessingPictureListener(in IActiveProcessingPictureListener l);

    List<ParameterCapability> getParameterCapabilities(in List<String> names, int userId);

+114 −10
Original line number Diff line number Diff line
@@ -42,9 +42,11 @@ import android.hardware.tv.mediaquality.SoundParameter;
import android.hardware.tv.mediaquality.SoundParameters;
import android.hardware.tv.mediaquality.StreamStatus;
import android.hardware.tv.mediaquality.VendorParamCapability;
import android.media.quality.ActiveProcessingPicture;
import android.media.quality.AmbientBacklightEvent;
import android.media.quality.AmbientBacklightMetadata;
import android.media.quality.AmbientBacklightSettings;
import android.media.quality.IActiveProcessingPictureListener;
import android.media.quality.IAmbientBacklightCallback;
import android.media.quality.IMediaQualityManager;
import android.media.quality.IPictureProfileCallback;
@@ -72,6 +74,8 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.SurfaceControlActivePicture;
import android.view.SurfaceControlActivePictureListener;

import com.android.internal.annotations.GuardedBy;
import com.android.server.SystemService;
@@ -121,6 +125,7 @@ public class MediaQualityService extends SystemService {
    private MqManagerNotifier mMqManagerNotifier;
    private MqDatabaseUtils mMqDatabaseUtils;
    private Handler mHandler;
    private SurfaceControlActivePictureListener mSurfaceControlActivePictureListener;

    // A global lock for picture profile objects.
    private final Object mPictureProfileLock = new Object();
@@ -175,6 +180,14 @@ public class MediaQualityService extends SystemService {
        }
        Slogf.d(TAG, "Binder is not null");

        mSurfaceControlActivePictureListener = new SurfaceControlActivePictureListener() {
            @Override
            public void onActivePicturesChanged(SurfaceControlActivePicture[] activePictures) {
                handleOnActivePicturesChanged(activePictures);
            }
        };
        mSurfaceControlActivePictureListener.startListening(); // TODO: stop listening

        mMediaQuality = IMediaQuality.Stub.asInterface(binder);
        if (mMediaQuality != null) {
            try {
@@ -210,6 +223,54 @@ public class MediaQualityService extends SystemService {
        publishBinderService(Context.MEDIA_QUALITY_SERVICE, new BinderService());
    }

    private void handleOnActivePicturesChanged(SurfaceControlActivePicture[] scActivePictures) {
        if (DEBUG) {
            Slog.d(TAG, "handleOnActivePicturesChanged");
        }
        synchronized (mPictureProfileLock) {
        // TODO handle other users
            UserState userState = getOrCreateUserState(UserHandle.USER_SYSTEM);
            int n = userState.mActiveProcessingPictureCallbackList.beginBroadcast();
            for (int i = 0; i < n; ++i) {
                try {
                    IActiveProcessingPictureListener l = userState
                            .mActiveProcessingPictureCallbackList
                            .getBroadcastItem(i);
                    ActiveProcessingPictureListenerInfo info =
                            userState.mActiveProcessingPictureListenerMap.get(l);
                    if (info == null) {
                        continue;
                    }
                    int uid = info.mUid;
                    boolean hasGlobalPermission = mContext.checkPermission(
                            android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE,
                            info.mPid, uid)
                            == PackageManager.PERMISSION_GRANTED;
                    List<ActiveProcessingPicture> aps = new ArrayList<>();
                    for (SurfaceControlActivePicture scap : scActivePictures) {
                        if (!hasGlobalPermission && scap.getOwnerUid() != uid) {
                            // should not receive the event
                            continue;
                        }
                        String profileId = mPictureProfileTempIdMap.getValue(
                                scap.getPictureProfileHandle().getId());
                        if (profileId == null) {
                            continue;
                        }
                        aps.add(new ActiveProcessingPicture(
                                scap.getLayerId(), profileId, scap.getOwnerUid() != uid));

                    }

                    l.onActiveProcessingPicturesChanged(aps);
                } catch (RemoteException e) {
                    Slog.e(TAG, "failed to report added AD service to callback", e);
                }
            }
            userState.mActiveProcessingPictureCallbackList.finishBroadcast();
        }
    }

    private final class BinderService extends IMediaQualityManager.Stub {

        @GuardedBy("mPictureProfileLock")
@@ -801,21 +862,21 @@ public class MediaQualityService extends SystemService {
        }

        private boolean hasGlobalPictureQualityServicePermission() {
            return mPackageManager.checkPermission(android.Manifest.permission
                            .MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE,
                    mContext.getPackageName()) == mPackageManager.PERMISSION_GRANTED;
            return mContext.checkCallingPermission(
                    android.Manifest.permission.MANAGE_GLOBAL_PICTURE_QUALITY_SERVICE)
                    == PackageManager.PERMISSION_GRANTED;
        }

        private boolean hasGlobalSoundQualityServicePermission() {
            return mPackageManager.checkPermission(android.Manifest.permission
                            .MANAGE_GLOBAL_SOUND_QUALITY_SERVICE,
                    mContext.getPackageName()) == mPackageManager.PERMISSION_GRANTED;
            return mContext.checkCallingPermission(
                    android.Manifest.permission.MANAGE_GLOBAL_SOUND_QUALITY_SERVICE)
                    == PackageManager.PERMISSION_GRANTED;
        }

        private boolean hasReadColorZonesPermission() {
            return mPackageManager.checkPermission(android.Manifest.permission
                            .READ_COLOR_ZONES,
                    mContext.getPackageName()) == mPackageManager.PERMISSION_GRANTED;
            return mContext.checkCallingPermission(
                    android.Manifest.permission.READ_COLOR_ZONES)
                    == PackageManager.PERMISSION_GRANTED;
        }

        @Override
@@ -838,6 +899,18 @@ public class MediaQualityService extends SystemService {
                    Pair.create(callingPid, callingUid));
        }

        @Override
        public void registerActiveProcessingPictureListener(
                final IActiveProcessingPictureListener l) {
            int callingPid = Binder.getCallingPid();
            int callingUid = Binder.getCallingUid();

            UserState userState = getOrCreateUserState(Binder.getCallingUid());
            String packageName = getPackageOfCallingUid();
            userState.mActiveProcessingPictureListenerMap.put(l,
                    new ActiveProcessingPictureListenerInfo(callingUid, callingPid, packageName));
        }

        @Override
        public void registerAmbientBacklightCallback(IAmbientBacklightCallback callback) {
            if (DEBUG) {
@@ -1245,6 +1318,20 @@ public class MediaQualityService extends SystemService {
        }
    }

    private class ActiveProcessingPictureCallbackList extends
            RemoteCallbackList<IActiveProcessingPictureListener> {
        @Override
        public void onCallbackDied(IActiveProcessingPictureListener l) {
            synchronized (mPictureProfileLock) {
                for (int i = 0; i < mUserStates.size(); i++) {
                    int userId = mUserStates.keyAt(i);
                    UserState userState = getOrCreateUserState(userId);
                    userState.mActiveProcessingPictureListenerMap.remove(l);
                }
            }
        }
    }

    private final class UserState {
        // A list of callbacks.
        private final MediaQualityManagerPictureProfileCallbackList mPictureProfileCallbacks =
@@ -1253,18 +1340,35 @@ public class MediaQualityService extends SystemService {
        private final MediaQualityManagerSoundProfileCallbackList mSoundProfileCallbacks =
                new MediaQualityManagerSoundProfileCallbackList();

        private final ActiveProcessingPictureCallbackList mActiveProcessingPictureCallbackList =
                new ActiveProcessingPictureCallbackList();

        private final Map<IPictureProfileCallback, Pair<Integer, Integer>>
                mPictureProfileCallbackPidUidMap = new HashMap<>();

        private final Map<ISoundProfileCallback, Pair<Integer, Integer>>
                mSoundProfileCallbackPidUidMap = new HashMap<>();

        private final Map<IActiveProcessingPictureListener, ActiveProcessingPictureListenerInfo>
                mActiveProcessingPictureListenerMap = new HashMap<>();

        private UserState(Context context, int userId) {

        }
    }

    @GuardedBy("mUserStateLock")
    private final class ActiveProcessingPictureListenerInfo {
        private int mUid;
        private int mPid;
        private String mPackageName;

        ActiveProcessingPictureListenerInfo(int uid, int pid, String packageName) {
            mUid = uid;
            mPid = pid;
            mPackageName = packageName;
        }
    }

    private UserState getOrCreateUserState(int userId) {
        UserState userState = getUserState(userId);
        if (userState == null) {