107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik/*
207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Copyright (C) 2014 The Android Open Source Project
307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *
407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Licensed under the Apache License, Version 2.0 (the "License");
507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * you may not use this file except in compliance with the License.
607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * You may obtain a copy of the License at
707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *
807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *      http://www.apache.org/licenses/LICENSE-2.0
907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik *
1007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * Unless required by applicable law or agreed to in writing, software
1107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * distributed under the License is distributed on an "AS IS" BASIS,
1207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * See the License for the specific language governing permissions and
1407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik * limitations under the License.
1507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik */
16bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpackage com.android.onemedia.playback;
17bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
18bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.Context;
19bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.media.MediaPlayer;
20bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.Bundle;
21bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
22bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport java.util.ArrayList;
23bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport java.util.List;
24bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
25bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik/**
26bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik * TODO: Insert description here. (generated by epastern)
27bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik */
28bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpublic abstract class Renderer {
29bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_SET_CONTENT = "com.android.media.SET_CONTENT";
30bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_SET_NEXT_CONTENT = "com.android.media.SET_NEXT_CONTENT";
31bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_PLAY = "com.android.media.PLAY";
32bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_PAUSE = "com.android.media.PAUSE";
33bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_NEXT = "com.android.media.NEXT";
34bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_PREVIOUS = "com.android.media.PREVIOUS";
35bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_SEEK_TO = "com.android.media.SEEK_TO";
36bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final String FEATURE_STOP = "com.android.media.STOP";
37bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // TODO move states somewhere else
38bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_ERROR = 0;
39bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
40bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The state MediaPlayerManager starts in before any action has been
41bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * performed.
42bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
43bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_INIT = 1 << 0;
44bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
45bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * Indicates the source has been set and it is being prepared/buffered
46bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * before starting playback.
47bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
48bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_PREPARING = 1 << 1;
49bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
50bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The media is ready and playback can be started.
51bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
52bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_READY = 1 << 2;
53bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
54bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The media is currently playing.
55bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
56bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_PLAYING = 1 << 3;
57bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
58bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The media is currently paused.
59bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
60bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_PAUSED = 1 << 4;
61bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
62bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The service has been stopped and cannot be started again until a new
63bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * source has been set.
64bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
65bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_STOPPED = 1 << 5;
66bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    /**
67bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     * The playback has reached the end. It can be restarted by calling play().
68bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik     */
69bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public static final int STATE_ENDED = 1 << 6;
70bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
71bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    // TODO decide on proper way of describing features
72bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected List<String> mFeatures = new ArrayList<String>();
73bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected List<Listener> mListeners = new ArrayList<Listener>();
74bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
75bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public Renderer(Context context, Bundle params) {
76bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        onCreate(params);
77bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        initFeatures(params);
78bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
79bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
80bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    abstract public void setContent(Bundle request);
81bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
82bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onCreate(Bundle params) {
83bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        // Do nothing by default
84bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
85bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
86bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void setNextContent(Bundle request) {
87bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        throw new UnsupportedOperationException("setNextContent() is not supported.");
88bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
89bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
90bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public List<String> getFeatures() {
91bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return mFeatures;
92bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
93bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
94bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onPlay() {
9507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // TODO consider making these log warnings instead of crashes (or
9607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // Log.wtf)
9707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new UnsupportedOperationException("play is not supported.");
9807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return false;
99bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
100bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
101bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onPause() {
10207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new UnsupportedOperationException("pause is not supported.");
10307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return false;
104bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
105bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
106bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onNext() {
10707c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new UnsupportedOperationException("next is not supported.");
10807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return false;
109bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
110bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
111bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onPrevious() {
11207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new
11307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // UnsupportedOperationException("previous is not supported.");
11407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return false;
115bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
116bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
117bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onStop() {
11807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new UnsupportedOperationException("stop is not supported.");
11907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return false;
120bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
121bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
122bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public boolean onSeekTo(int time) {
12307c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new UnsupportedOperationException("seekTo is not supported.");
12407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return false;
125bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
126bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
127bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public long getSeekPosition() {
12807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new
12907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // UnsupportedOperationException("getSeekPosition is not supported.");
13007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return -1;
131bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
132bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
133bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public long getDuration() {
13407c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new
13507c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // UnsupportedOperationException("getDuration is not supported.");
13607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return -1;
137bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
138bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
139bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public int getPlayState() {
14007c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // throw new
14107c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        // UnsupportedOperationException("getPlayState is not supported.");
14207c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik        return 0;
143bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
144bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
145bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onDestroy() {
146bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        // Do nothing by default
147bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
148bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
149bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void registerListener(Listener listener) {
150bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (!mListeners.contains(listener)) {
151bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mListeners.add(listener);
152bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
153bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
154bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
155bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void unregisterListener(Listener listener) {
156bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mListeners.remove(listener);
157bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
158bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
159bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void initFeatures(Bundle params) {
160bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mFeatures.add(FEATURE_SET_CONTENT);
161bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
162bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
163bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void pushOnError(int type, int extra, Bundle extras, Throwable error) {
164bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        for (Listener listener : mListeners) {
165bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            listener.onError(type, extra, extras, error);
166bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
167bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
168bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
169bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void pushOnStateChanged(int newState) {
170bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        for (Listener listener : mListeners) {
171bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            listener.onStateChanged(newState);
172bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
173bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
174bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
175bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void pushOnBufferingUpdate(int percent) {
176bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        for (Listener listener : mListeners) {
177bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            listener.onBufferingUpdate(percent);
178bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
179bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
180bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
181bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void pushOnFocusLost() {
182bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        for (Listener listener : mListeners) {
183bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            listener.onFocusLost();
184bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
185bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
186bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
187bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected void pushOnNextStarted() {
188bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        for (Listener listener : mListeners) {
189bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            listener.onNextStarted();
190bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
191bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
192bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
193bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public interface Listener {
194bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public static final int ERROR_LOAD_FAILED = 1770;
195bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public static final int ERROR_PREPARE_ERROR = 1771;
196bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public static final int ERROR_PLAYBACK_FAILED = 1772;
197bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
198bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        /**
199bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * When an error occurs onError will be called but not onStateChanged.
200bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * The Manager will remain in the error state until
201bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * {@link #setContent()} is called again.
202bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         */
203bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void onError(int type, int extra, Bundle extras,
204bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                Throwable error);
205bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
206bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        /**
207bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * onStateChanged will be called whenever the state of the manager
208bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * transitions except to an error state.
209bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         */
210bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void onStateChanged(int newState);
211bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
212bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        /**
213bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * This is a passthrough of
214bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * {@link MediaPlayer.OnBufferingUpdateListener}.
215bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         */
216bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void onBufferingUpdate(int percent);
217bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
218bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        /**
219bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * Called when audio focus is lost and it is not transient or ducking.
220bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         */
221bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void onFocusLost();
222bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
223bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        /**
224bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * Called when the next item was started playing. Only called if a next
225bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         * item has been set and the current item has ended.
226bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik         */
227bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void onNextStarted();
228bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
229bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik}
230