From b52816e94d9d81734a684eca196f208abd702d53 Mon Sep 17 00:00:00 2001 From: yixiaoluo Date: Sat, 16 Oct 2021 00:40:43 +0000 Subject: [PATCH] Noogler Project: TIF broadcast request & response (initial) Bug: 203253534 Change-Id: I534be8fb54217604d9a7ba53e19c708175ab8d35 --- .../media/tv/BroadcastInfoRequest.aidl | 19 ++++++ .../media/tv/BroadcastInfoRequest.java | 58 +++++++++++++++++++ .../media/tv/BroadcastInfoResponse.aidl | 19 ++++++ .../media/tv/BroadcastInfoResponse.java | 58 +++++++++++++++++++ .../java/android/media/tv/ITvInputClient.aidl | 4 ++ .../android/media/tv/ITvInputManager.aidl | 4 ++ .../android/media/tv/ITvInputSession.aidl | 4 ++ .../media/tv/ITvInputSessionCallback.aidl | 4 ++ .../media/tv/ITvInputSessionWrapper.java | 10 ++++ .../java/android/media/tv/TvInputManager.java | 41 +++++++++++++ .../java/android/media/tv/TvInputService.java | 34 +++++++++++ .../server/tv/TvInputManagerService.java | 42 ++++++++++++++ 12 files changed, 297 insertions(+) create mode 100644 media/java/android/media/tv/BroadcastInfoRequest.aidl create mode 100644 media/java/android/media/tv/BroadcastInfoRequest.java create mode 100644 media/java/android/media/tv/BroadcastInfoResponse.aidl create mode 100644 media/java/android/media/tv/BroadcastInfoResponse.java diff --git a/media/java/android/media/tv/BroadcastInfoRequest.aidl b/media/java/android/media/tv/BroadcastInfoRequest.aidl new file mode 100644 index 0000000000000..26cdcc5a3fbeb --- /dev/null +++ b/media/java/android/media/tv/BroadcastInfoRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 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.tv; + +parcelable BroadcastInfoRequest; diff --git a/media/java/android/media/tv/BroadcastInfoRequest.java b/media/java/android/media/tv/BroadcastInfoRequest.java new file mode 100644 index 0000000000000..6077f04786745 --- /dev/null +++ b/media/java/android/media/tv/BroadcastInfoRequest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 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.tv; + +import android.os.Parcel; +import android.os.Parcelable; + +import android.annotation.NonNull; + +/** @hide */ +public final class BroadcastInfoRequest implements Parcelable { + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public BroadcastInfoRequest createFromParcel(Parcel source) { + return new BroadcastInfoRequest(source); + } + + @Override + public BroadcastInfoRequest[] newArray(int size) { + return new BroadcastInfoRequest[size]; + } + }; + + int requestId; + + public BroadcastInfoRequest(int requestId) { + this.requestId = requestId; + } + + private BroadcastInfoRequest(Parcel source) { + requestId = source.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(requestId); + } +} diff --git a/media/java/android/media/tv/BroadcastInfoResponse.aidl b/media/java/android/media/tv/BroadcastInfoResponse.aidl new file mode 100644 index 0000000000000..65e65b215400a --- /dev/null +++ b/media/java/android/media/tv/BroadcastInfoResponse.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 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.tv; + +parcelable BroadcastInfoResponse; diff --git a/media/java/android/media/tv/BroadcastInfoResponse.java b/media/java/android/media/tv/BroadcastInfoResponse.java new file mode 100644 index 0000000000000..64c884ec4b7fb --- /dev/null +++ b/media/java/android/media/tv/BroadcastInfoResponse.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 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.tv; + +import android.os.Parcel; +import android.os.Parcelable; + +import android.annotation.NonNull; + +/** @hide */ +public final class BroadcastInfoResponse implements Parcelable { + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public BroadcastInfoResponse createFromParcel(Parcel source) { + return new BroadcastInfoResponse(source); + } + + @Override + public BroadcastInfoResponse[] newArray(int size) { + return new BroadcastInfoResponse[size]; + } + }; + + int requestId; + + public BroadcastInfoResponse(int requestId) { + this.requestId = requestId; + } + + private BroadcastInfoResponse(Parcel source) { + requestId = source.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(requestId); + } +} diff --git a/media/java/android/media/tv/ITvInputClient.aidl b/media/java/android/media/tv/ITvInputClient.aidl index 72f8b5773c9ef..5dad633a0236d 100644 --- a/media/java/android/media/tv/ITvInputClient.aidl +++ b/media/java/android/media/tv/ITvInputClient.aidl @@ -22,6 +22,7 @@ import android.net.Uri; import android.media.tv.TvTrackInfo; import android.os.Bundle; import android.view.InputChannel; +import android.media.tv.BroadcastInfoResponse; /** * Interface a client of the ITvInputManager implements, to identify itself and receive information @@ -48,4 +49,7 @@ oneway interface ITvInputClient { void onTuned(int seq, in Uri channelUri); void onRecordingStopped(in Uri recordedProgramUri, int seq); void onError(int error, int seq); + + // For broadcast info + void onBroadcastInfoResponse(in BroadcastInfoResponse response, int seq); } diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index d8d1ba1341bb1..eaf89ba617648 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -35,6 +35,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.view.Surface; +import android.media.tv.BroadcastInfoRequest; /** * Interface to the TV input manager service. @@ -97,6 +98,9 @@ interface ITvInputManager { void pauseRecording(in IBinder sessionToken, in Bundle params, int userId); void resumeRecording(in IBinder sessionToken, in Bundle params, int userId); + // For broadcast info + void requestBroadcastInfo(in IBinder sessionToken, in BroadcastInfoRequest request, int userId); + // For TV input hardware binding List getHardwareList(); ITvInputHardware acquireTvInputHardware(int deviceId, in ITvInputHardwareCallback callback, diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl index 158cf211d9f04..1eab650ba953b 100644 --- a/media/java/android/media/tv/ITvInputSession.aidl +++ b/media/java/android/media/tv/ITvInputSession.aidl @@ -22,6 +22,7 @@ import android.media.tv.TvTrackInfo; import android.net.Uri; import android.os.Bundle; import android.view.Surface; +import android.media.tv.BroadcastInfoRequest; /** * Sub-interface of ITvInputService which is created per session and has its own context. @@ -60,4 +61,7 @@ oneway interface ITvInputSession { void stopRecording(); void pauseRecording(in Bundle params); void resumeRecording(in Bundle params); + + // For broadcast info + void requestBroadcastInfo(in BroadcastInfoRequest request); } diff --git a/media/java/android/media/tv/ITvInputSessionCallback.aidl b/media/java/android/media/tv/ITvInputSessionCallback.aidl index af76f9033b254..d857c00d8279b 100644 --- a/media/java/android/media/tv/ITvInputSessionCallback.aidl +++ b/media/java/android/media/tv/ITvInputSessionCallback.aidl @@ -20,6 +20,7 @@ import android.media.tv.ITvInputSession; import android.net.Uri; import android.media.tv.TvTrackInfo; import android.os.Bundle; +import android.media.tv.BroadcastInfoResponse; /** * Helper interface for ITvInputSession to allow the TV input to notify the system service when a @@ -45,4 +46,7 @@ oneway interface ITvInputSessionCallback { void onTuned(in Uri channelUri); void onRecordingStopped(in Uri recordedProgramUri); void onError(int error); + + // For broadcast info + void onBroadcastInfoResponse(in BroadcastInfoResponse response); } diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java index abccf8da9cfce..425714582fd58 100644 --- a/media/java/android/media/tv/ITvInputSessionWrapper.java +++ b/media/java/android/media/tv/ITvInputSessionWrapper.java @@ -70,6 +70,7 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand private static final int DO_STOP_RECORDING = 21; private static final int DO_PAUSE_RECORDING = 22; private static final int DO_RESUME_RECORDING = 23; + private static final int DO_REQUEST_BROADCAST_INFO = 24; private final boolean mIsRecordingSession; private final HandlerCaller mCaller; @@ -234,6 +235,10 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mTvInputRecordingSessionImpl.resumeRecording((Bundle) msg.obj); break; } + case DO_REQUEST_BROADCAST_INFO: { + mTvInputSessionImpl.requestBroadcastInfo((BroadcastInfoRequest) msg.obj); + break; + } default: { Log.w(TAG, "Unhandled message code: " + msg.what); break; @@ -383,6 +388,11 @@ public class ITvInputSessionWrapper extends ITvInputSession.Stub implements Hand mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RESUME_RECORDING, params)); } + @Override + public void requestBroadcastInfo(BroadcastInfoRequest request) { + mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_REQUEST_BROADCAST_INFO, request)); + } + private final class TvInputEventReceiver extends InputEventReceiver { public TvInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 34e4609a71f73..f22b7dce8e9fa 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -656,6 +656,13 @@ public final class TvInputManager { */ void onError(Session session, @TvInputManager.RecordingError int error) { } + + /** + * @param session + * @param response + */ + public void onBroadcastInfoResponse(Session session, BroadcastInfoResponse response) { + } } private static final class SessionCallbackRecord { @@ -835,6 +842,15 @@ public final class TvInputManager { } }); } + + void postBroadcastInfoResponse(final BroadcastInfoResponse response) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onBroadcastInfoResponse(mSession, response); + } + }); + } } /** @@ -1233,6 +1249,18 @@ public final class TvInputManager { record.postError(error); } } + + @Override + public void onBroadcastInfoResponse(BroadcastInfoResponse response, int seq) { + synchronized (mSessionCallbackRecordMap) { + SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq); + if (record == null) { + Log.e(TAG, "Callback not found for seq " + seq); + return; + } + record.postBroadcastInfoResponse(response); + } + } }; ITvInputManagerCallback managerCallback = new ITvInputManagerCallback.Stub() { @Override @@ -2839,6 +2867,19 @@ public final class TvInputManager { } } + public void requestBroadcastInfo(BroadcastInfoRequest request) { + if (mToken == null) { + Log.w(TAG, "The session has been already released"); + return; + } + try { + mService.requestBroadcastInfo(mToken, request, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + } + private final class InputEventHandler extends Handler { public static final int MSG_SEND_INPUT_EVENT = 1; public static final int MSG_TIMEOUT_INPUT_EVENT = 2; diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 77fb2b2366989..f312f64b140ec 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -769,6 +769,29 @@ public abstract class TvInputService extends Service { }); } + /** + * Notifies response for broadcast info. + * + * @param response + * @hide + */ + public void notifyBroadcastInfoResponse(@NonNull final BroadcastInfoResponse response) { + executeOrPostRunnableOnMainThread(new Runnable() { + @MainThread + @Override + public void run() { + try { + if (DEBUG) Log.d(TAG, "notifyBroadcastInfoResponse"); + if (mSessionCallback != null) { + mSessionCallback.onBroadcastInfoResponse(response); + } + } catch (RemoteException e) { + Log.w(TAG, "error in notifyBroadcastInfoResponse", e); + } + } + }); + } + private void notifyTimeShiftStartPositionChanged(final long timeMs) { executeOrPostRunnableOnMainThread(new Runnable() { @MainThread @@ -916,6 +939,13 @@ public abstract class TvInputService extends Service { */ public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume); + /** + * @param request broadcast info request + * @hide + */ + public void onRequestBroadcastInfo(@NonNull BroadcastInfoRequest request) { + } + /** * Tunes to a given channel. * @@ -1506,6 +1536,10 @@ public abstract class TvInputService extends Service { } } + void requestBroadcastInfo(BroadcastInfoRequest request) { + onRequestBroadcastInfo(request); + } + /** * Takes care of dispatching incoming input events and tells whether the event was handled. */ diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 28947083854bd..87ce1cea47b9e 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -44,6 +44,8 @@ import android.graphics.Rect; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.media.PlaybackParams; +import android.media.tv.BroadcastInfoRequest; +import android.media.tv.BroadcastInfoResponse; import android.media.tv.DvbDeviceInfo; import android.media.tv.ITvInputClient; import android.media.tv.ITvInputHardware; @@ -2326,6 +2328,29 @@ public final class TvInputManagerService extends SystemService { } } + @Override + public void requestBroadcastInfo(IBinder sessionToken, BroadcastInfoRequest request, + int userId) { + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + final int resolvedUserId = resolveCallingUserId(callingPid, callingUid, + userId, "requestBroadcastInfo"); + final long identity = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + try { + SessionState sessionState = getSessionStateLocked(sessionToken, callingUid, + resolvedUserId); + getSessionLocked(sessionState).requestBroadcastInfo(request); + } catch (RemoteException | SessionNotFoundException e) { + Slog.e(TAG, "error in requestBroadcastInfo", e); + } + } + } finally { + Binder.restoreCallingIdentity(identity); + }; + } + @Override public int getClientPid(String sessionId) { ensureTunerResourceAccessPermission(); @@ -3342,6 +3367,23 @@ public final class TvInputManagerService extends SystemService { } } } + + @Override + public void onBroadcastInfoResponse (BroadcastInfoResponse response) { + synchronized (mLock) { + if (DEBUG) { + Slog.d(TAG, "onBroadcastInfoResponse()"); + } + if (mSessionState.session == null || mSessionState.client == null) { + return; + } + try { + mSessionState.client.onBroadcastInfoResponse(response, mSessionState.seq); + } catch (RemoteException e) { + Slog.e(TAG, "error in onBroadcastInfoResponse", e); + } + } + } } @VisibleForTesting