1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.tv.common.support.tis;
17 
18 import android.annotation.TargetApi;
19 import android.media.PlaybackParams;
20 import android.media.tv.TvContentRating;
21 import android.media.tv.TvInputManager;
22 import android.media.tv.TvInputService.Session;
23 import android.media.tv.TvTrackInfo;
24 import android.net.Uri;
25 import android.os.Build;
26 import android.os.Build.VERSION_CODES;
27 import android.support.annotation.FloatRange;
28 import android.support.annotation.NonNull;
29 import android.support.annotation.Nullable;
30 import android.view.Surface;
31 import android.view.View;
32 import java.util.List;
33 
34 /**
35  * Custom {@link android.media.tv.TvInputService.Session} class that uses delegation and a callback
36  * to separate it from the TvInputService for easier testing.
37  */
38 public abstract class TifSession {
39 
40     private final TifSessionCallbacks callback;
41 
42     /**
43      * Creates TV Input Framework Session with the given callback.
44      *
45      * <p>The callback is used to pass notification to the actual {@link
46      * android.media.tv.TvInputService.Session}.
47      *
48      * <p>Pass a mock callback for tests.
49      */
TifSession(TifSessionCallbacks callback)50     protected TifSession(TifSessionCallbacks callback) {
51         this.callback = callback;
52     }
53 
54     /**
55      * Called after this session had been created and the callback is attached.
56      *
57      * <p>Do not call notify methods in the constructor, instead call them here if needed at
58      * creation time. eg @{@link Session#notifyTimeShiftStatusChanged(int)}.
59      */
onSessionCreated()60     public void onSessionCreated() {}
61 
62     /** @see Session#onRelease() */
onRelease()63     public void onRelease() {}
64 
65     /** @see Session#onSetSurface(Surface) */
onSetSurface(@ullable Surface surface)66     public abstract boolean onSetSurface(@Nullable Surface surface);
67 
68     /** @see Session#onSurfaceChanged(int, int, int) */
onSurfaceChanged(int format, int width, int height)69     public abstract void onSurfaceChanged(int format, int width, int height);
70 
71     /** @see Session#onSetStreamVolume(float) */
onSetStreamVolume(@loatRangefrom = 0.0, to = 1.0) float volume)72     public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
73 
74     /** @see Session#onTune(Uri) */
onTune(Uri channelUri)75     public abstract boolean onTune(Uri channelUri);
76 
77     /** @see Session#onSetCaptionEnabled(boolean) */
onSetCaptionEnabled(boolean enabled)78     public abstract void onSetCaptionEnabled(boolean enabled);
79 
80     /** @see Session#onUnblockContent(TvContentRating) */
onUnblockContent(TvContentRating unblockedRating)81     public abstract void onUnblockContent(TvContentRating unblockedRating);
82 
83     /** @see Session#onTimeShiftGetCurrentPosition() */
84     @TargetApi(Build.VERSION_CODES.M)
onTimeShiftGetCurrentPosition()85     public long onTimeShiftGetCurrentPosition() {
86         return TvInputManager.TIME_SHIFT_INVALID_TIME;
87     }
88 
89     /** @see Session#onTimeShiftGetStartPosition() */
90     @TargetApi(Build.VERSION_CODES.M)
onTimeShiftGetStartPosition()91     public long onTimeShiftGetStartPosition() {
92         return TvInputManager.TIME_SHIFT_INVALID_TIME;
93     }
94 
95     /** @see Session#onTimeShiftPause() */
96     @TargetApi(Build.VERSION_CODES.M)
onTimeShiftPause()97     public void onTimeShiftPause() {}
98 
99     /** @see Session#onTimeShiftResume() */
100     @TargetApi(Build.VERSION_CODES.M)
onTimeShiftResume()101     public void onTimeShiftResume() {}
102 
103     /** @see Session#onTimeShiftSeekTo(long) */
104     @TargetApi(Build.VERSION_CODES.M)
onTimeShiftSeekTo(long timeMs)105     public void onTimeShiftSeekTo(long timeMs) {}
106 
107     /** @see Session#onTimeShiftSetPlaybackParams(PlaybackParams) */
108     @TargetApi(Build.VERSION_CODES.M)
onTimeShiftSetPlaybackParams(PlaybackParams params)109     public void onTimeShiftSetPlaybackParams(PlaybackParams params) {}
110 
onParentalControlsChanged()111     public void onParentalControlsChanged() {}
112 
113     /** @see Session#notifyChannelRetuned(Uri) */
notifyChannelRetuned(final Uri channelUri)114     public final void notifyChannelRetuned(final Uri channelUri) {
115         callback.notifyChannelRetuned(channelUri);
116     }
117 
118     /** @see Session#notifyTracksChanged(List) */
notifyTracksChanged(final List<TvTrackInfo> tracks)119     public final void notifyTracksChanged(final List<TvTrackInfo> tracks) {
120         callback.notifyTracksChanged(tracks);
121     }
122 
123     /** @see Session#notifyTrackSelected(int, String) */
notifyTrackSelected(final int type, final String trackId)124     public final void notifyTrackSelected(final int type, final String trackId) {
125         callback.notifyTrackSelected(type, trackId);
126     }
127 
128     /** @see Session#notifyVideoAvailable() */
notifyVideoAvailable()129     public final void notifyVideoAvailable() {
130         callback.notifyVideoAvailable();
131     }
132 
133     /** @see Session#notifyVideoUnavailable(int) */
notifyVideoUnavailable(final int reason)134     public final void notifyVideoUnavailable(final int reason) {
135         callback.notifyVideoUnavailable(reason);
136     }
137 
138     /** @see Session#notifyContentAllowed() */
notifyContentAllowed()139     public final void notifyContentAllowed() {
140         callback.notifyContentAllowed();
141     }
142 
143     /** @see Session#notifyContentBlocked(TvContentRating) */
notifyContentBlocked(@onNull final TvContentRating rating)144     public final void notifyContentBlocked(@NonNull final TvContentRating rating) {
145         callback.notifyContentBlocked(rating);
146     }
147 
148     /** @see Session#notifyTimeShiftStatusChanged(int) */
149     @TargetApi(VERSION_CODES.M)
notifyTimeShiftStatusChanged(final int status)150     public final void notifyTimeShiftStatusChanged(final int status) {
151         callback.notifyTimeShiftStatusChanged(status);
152     }
153 
154     /** @see Session#setOverlayViewEnabled(boolean) */
setOverlayViewEnabled(boolean enabled)155     public void setOverlayViewEnabled(boolean enabled) {
156         callback.setOverlayViewEnabled(enabled);
157     }
158 
159     /** @see Session#onCreateOverlayView() */
onCreateOverlayView()160     public View onCreateOverlayView() {
161         return null;
162     }
163 
164     /** @see Session#onOverlayViewSizeChanged(int, int) */
onOverlayViewSizeChanged(int width, int height)165     public void onOverlayViewSizeChanged(int width, int height) {}
166 
167     /**
168      * Callbacks used to notify the {@link android.media.tv.TvInputService.Session}.
169      *
170      * <p>This is implemented internally by {@link WrappedSession}, and can be mocked for tests.
171      */
172     public interface TifSessionCallbacks {
173         /** @see Session#notifyChannelRetuned(Uri) */
notifyChannelRetuned(final Uri channelUri)174         void notifyChannelRetuned(final Uri channelUri);
175         /** @see Session#notifyTracksChanged(List) */
notifyTracksChanged(final List<TvTrackInfo> tracks)176         void notifyTracksChanged(final List<TvTrackInfo> tracks);
177         /** @see Session#notifyTrackSelected(int, String) */
notifyTrackSelected(final int type, final String trackId)178         void notifyTrackSelected(final int type, final String trackId);
179         /** @see Session#notifyVideoAvailable() */
notifyVideoAvailable()180         void notifyVideoAvailable();
181         /** @see Session#notifyVideoUnavailable(int) */
notifyVideoUnavailable(final int reason)182         void notifyVideoUnavailable(final int reason);
183         /** @see Session#notifyContentAllowed() */
notifyContentAllowed()184         void notifyContentAllowed();
185         /** @see Session#notifyContentBlocked(TvContentRating) */
notifyContentBlocked(@onNull final TvContentRating rating)186         void notifyContentBlocked(@NonNull final TvContentRating rating);
187         /** @see Session#notifyTimeShiftStatusChanged(int) */
188         @TargetApi(VERSION_CODES.M)
notifyTimeShiftStatusChanged(final int status)189         void notifyTimeShiftStatusChanged(final int status);
190         /** @see Session#setOverlayViewEnabled(boolean) */
setOverlayViewEnabled(boolean enabled)191         void setOverlayViewEnabled(boolean enabled);
192     }
193 
194     /**
195      * Creates a {@link TifSession}.
196      *
197      * <p>This is used by {@link WrappedSession} to create the desired {@code TifSession}. Should be
198      * used with <a href="http://go/autofactory">go/autofactory</a>.
199      */
200     public interface TifSessionFactory {
create(TifSessionCallbacks callbacks, String inputId)201         TifSession create(TifSessionCallbacks callbacks, String inputId);
202     }
203 }
204