summaryrefslogtreecommitdiffstats
path: root/core/java/android/tv/TvInputService.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/tv/TvInputService.java')
-rw-r--r--core/java/android/tv/TvInputService.java205
1 files changed, 191 insertions, 14 deletions
diff --git a/core/java/android/tv/TvInputService.java b/core/java/android/tv/TvInputService.java
index 80eb407..636e3b4 100644
--- a/core/java/android/tv/TvInputService.java
+++ b/core/java/android/tv/TvInputService.java
@@ -28,13 +28,21 @@ import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.tv.TvInputManager.Session;
import android.util.Log;
import android.view.Gravity;
+import android.view.InputChannel;
+import android.view.InputDevice;
+import android.view.InputEvent;
+import android.view.InputEventReceiver;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
/**
* A base class for implementing television input service.
@@ -89,10 +97,17 @@ public abstract class TvInputService extends Service {
}
@Override
- public void createSession(ITvInputSessionCallback cb) {
- if (cb != null) {
- mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, cb).sendToTarget();
+ public void createSession(InputChannel channel, ITvInputSessionCallback cb) {
+ if (channel == null) {
+ Log.w(TAG, "Creating session without input channel");
+ }
+ if (cb == null) {
+ return;
}
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = channel;
+ args.arg2 = cb;
+ mHandler.obtainMessage(ServiceHandler.DO_CREATE_SESSION, args).sendToTarget();
}
};
}
@@ -131,7 +146,8 @@ public abstract class TvInputService extends Service {
/**
* Base class for derived classes to implement to provide {@link TvInputManager.Session}.
*/
- public abstract class TvInputSessionImpl {
+ public abstract class TvInputSessionImpl implements KeyEvent.Callback {
+ private final KeyEvent.DispatcherState mDispatcherState = new KeyEvent.DispatcherState();
private final WindowManager mWindowManager;
private WindowManager.LayoutParams mWindowParams;
private View mOverlayView;
@@ -143,6 +159,13 @@ public abstract class TvInputService extends Service {
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
}
+ /**
+ * Enables or disables the overlay view. By default, the overlay view is disabled. Must be
+ * called explicitly after the session is created to enable the overlay view.
+ *
+ * @param enable {@code true} if you want to enable the overlay view. {@code false}
+ * otherwise.
+ */
public void setOverlayViewEnabled(final boolean enable) {
mHandler.post(new Runnable() {
@Override
@@ -203,6 +226,121 @@ public abstract class TvInputService extends Service {
}
/**
+ * Default implementation of {@link android.view.KeyEvent.Callback#onKeyDown(int, KeyEvent)
+ * KeyEvent.Callback.onKeyDown()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept key down events before they are processed by the application.
+ * If you return true, the application will not process the event itself. If you return
+ * false, the normal application processing will occur as if the TV input had not seen the
+ * event at all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Default implementation of
+ * {@link android.view.KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
+ * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept key long press events before they are processed by the
+ * application. If you return true, the application will not process the event itself. If
+ * you return false, the normal application processing will occur as if the TV input had not
+ * seen the event at all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Default implementation of
+ * {@link android.view.KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
+ * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept special key multiple events before they are processed by the
+ * application. If you return true, the application will not itself process the event. If
+ * you return false, the normal application processing will occur as if the TV input had not
+ * seen the event at all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param count The number of times the action was made.
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Default implementation of {@link android.view.KeyEvent.Callback#onKeyUp(int, KeyEvent)
+ * KeyEvent.Callback.onKeyUp()}: always returns false (doesn't handle the event).
+ * <p>
+ * Override this to intercept key up events before they are processed by the application. If
+ * you return true, the application will not itself process the event. If you return false,
+ * the normal application processing will occur as if the TV input had not seen the event at
+ * all.
+ *
+ * @param keyCode The value in event.getKeyCode().
+ * @param event Description of the key event.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ */
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ return false;
+ }
+
+ /**
+ * Implement this method to handle touch screen motion events on the current input session.
+ *
+ * @param event The motion event being received.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ * @see View#onTouchEvent
+ */
+ public boolean onTouchEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Implement this method to handle trackball events on the current input session.
+ *
+ * @param event The motion event being received.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ * @see View#onTrackballEvent
+ */
+ public boolean onTrackballEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Implement this method to handle generic motion events on the current input session.
+ *
+ * @param event The motion event being received.
+ * @return If you handled the event, return {@code true}. If you want to allow the event to
+ * be handled by the next receiver, return {@code false}.
+ * @see View#onGenericMotionEvent
+ */
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
* This method is called when the application would like to stop using the current input
* session.
*/
@@ -212,7 +350,7 @@ public abstract class TvInputService extends Service {
}
/**
- * Calls {@link onSetSurface}.
+ * Calls {@link #onSetSurface}.
*/
void setSurface(Surface surface) {
onSetSurface(surface);
@@ -220,14 +358,14 @@ public abstract class TvInputService extends Service {
}
/**
- * Calls {@link onSetVolume}.
+ * Calls {@link #onSetVolume}.
*/
void setVolume(float volume) {
onSetVolume(volume);
}
/**
- * Calls {@link onTune}.
+ * Calls {@link #onTune}.
*/
void tune(Uri channelUri) {
onTune(channelUri);
@@ -235,8 +373,8 @@ public abstract class TvInputService extends Service {
}
/**
- * Creates an overlay view. This calls {@link onCreateOverlayView} to get
- * a view to attach to the overlay window.
+ * Creates an overlay view. This calls {@link #onCreateOverlayView} to get a view to attach
+ * to the overlay window.
*
* @param windowToken A window token of an application.
* @param frame A position of the overlay view.
@@ -314,6 +452,42 @@ public abstract class TvInputService extends Service {
mWindowParams = null;
}
}
+
+ /**
+ * Takes care of dispatching incoming input events and tells whether the event was handled.
+ */
+ int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
+ if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")");
+ if (event instanceof KeyEvent) {
+ if (((KeyEvent) event).dispatch(this, mDispatcherState, this)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ } else if (event instanceof MotionEvent) {
+ MotionEvent motionEvent = (MotionEvent) event;
+ final int source = motionEvent.getSource();
+ if (motionEvent.isTouchEvent()) {
+ if (onTouchEvent(motionEvent)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+ if (onTrackballEvent(motionEvent)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ } else {
+ if (onGenericMotionEvent(motionEvent)) {
+ return Session.DISPATCH_HANDLED;
+ }
+ }
+ }
+ if (mOverlayView == null) {
+ return Session.DISPATCH_NOT_HANDLED;
+ }
+ if (!mOverlayView.hasWindowFocus()) {
+ mOverlayView.getViewRootImpl().windowFocusChanged(true, true);
+ }
+ mOverlayView.getViewRootImpl().dispatchInputEvent(event, receiver);
+ return Session.DISPATCH_IN_PROGRESS;
+ }
}
private final class ServiceHandler extends Handler {
@@ -324,20 +498,23 @@ public abstract class TvInputService extends Service {
public final void handleMessage(Message msg) {
switch (msg.what) {
case DO_CREATE_SESSION: {
- ITvInputSessionCallback cb = (ITvInputSessionCallback) msg.obj;
+ SomeArgs args = (SomeArgs) msg.obj;
+ InputChannel channel = (InputChannel) args.arg1;
+ ITvInputSessionCallback cb = (ITvInputSessionCallback) args.arg2;
try {
TvInputSessionImpl sessionImpl = onCreateSession();
if (sessionImpl == null) {
// Failed to create a session.
cb.onSessionCreated(null);
- return;
+ } else {
+ ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
+ sessionImpl, channel);
+ cb.onSessionCreated(stub);
}
- ITvInputSession stub = new ITvInputSessionWrapper(TvInputService.this,
- sessionImpl);
- cb.onSessionCreated(stub);
} catch (RemoteException e) {
Log.e(TAG, "error in onSessionCreated");
}
+ args.recycle();
return;
}
case DO_BROADCAST_AVAILABILITY_CHANGE: {