Merge "VDM demo: all repohooks fixed for client/" into main

This commit is contained in:
Treehugger Robot
2023-12-06 13:50:15 +00:00
committed by Android (Google) Code Review
11 changed files with 277 additions and 290 deletions

View File

@@ -47,25 +47,25 @@ final class AudioPlayer implements Consumer<RemoteEvent> {
SAMPLE_RATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT); SAMPLE_RATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
private static final int AUDIOTRACK_BUFFER_SIZE = 4 * MIN_AUDIOTRACK_BUFFER_SIZE; private static final int AUDIOTRACK_BUFFER_SIZE = 4 * MIN_AUDIOTRACK_BUFFER_SIZE;
private final Object lock = new Object(); private final Object mLock = new Object();
private AudioTrack audioTrack; private AudioTrack mAudioTrack;
@Inject @Inject
AudioPlayer() {} AudioPlayer() {}
private void startPlayback() { private void startPlayback() {
synchronized (lock) { synchronized (mLock) {
if (audioTrack != null) { if (mAudioTrack != null) {
Log.w(TAG, "Received startPlayback command without stopping the playback first"); Log.w(TAG, "Received startPlayback command without stopping the playback first");
stopPlayback(); stopPlayback();
} }
audioTrack = mAudioTrack =
new AudioTrack.Builder() new AudioTrack.Builder()
.setAudioFormat(AUDIO_FORMAT) .setAudioFormat(AUDIO_FORMAT)
.setAudioAttributes(AUDIO_ATTRIBUTES) .setAudioAttributes(AUDIO_ATTRIBUTES)
.setBufferSizeInBytes(AUDIOTRACK_BUFFER_SIZE) .setBufferSizeInBytes(AUDIOTRACK_BUFFER_SIZE)
.build(); .build();
audioTrack.play(); mAudioTrack.play();
} }
} }
@@ -76,14 +76,14 @@ final class AudioPlayer implements Consumer<RemoteEvent> {
return; return;
} }
int bytesWritten = 0; int bytesWritten = 0;
synchronized (lock) { synchronized (mLock) {
if (audioTrack == null) { if (mAudioTrack == null) {
Log.e(TAG, "Received audio frame, but audio track was not initialized yet"); Log.e(TAG, "Received audio frame, but audio track was not initialized yet");
return; return;
} }
while (bytesToWrite > 0) { while (bytesToWrite > 0) {
int ret = audioTrack.write(data, bytesWritten, bytesToWrite); int ret = mAudioTrack.write(data, bytesWritten, bytesToWrite);
if (ret <= 0) { if (ret <= 0) {
Log.e(TAG, "AudioTrack.write returned error code " + ret); Log.e(TAG, "AudioTrack.write returned error code " + ret);
} }
@@ -94,13 +94,13 @@ final class AudioPlayer implements Consumer<RemoteEvent> {
} }
private void stopPlayback() { private void stopPlayback() {
synchronized (lock) { synchronized (mLock) {
if (audioTrack == null) { if (mAudioTrack == null) {
Log.w(TAG, "Received stopPlayback command for already stopped playback"); Log.w(TAG, "Received stopPlayback command for already stopped playback");
} else { } else {
audioTrack.stop(); mAudioTrack.stop();
audioTrack.release(); mAudioTrack.release();
audioTrack = null; mAudioTrack = null;
} }
} }
} }

View File

@@ -30,12 +30,12 @@ import java.util.function.Consumer;
/** Recycler view that can resize a child dynamically. */ /** Recycler view that can resize a child dynamically. */
public final class ClientView extends RecyclerView { public final class ClientView extends RecyclerView {
private boolean isResizing = false; private boolean mIsResizing = false;
private Consumer<Rect> resizeDoneCallback = null; private Consumer<Rect> mResizeDoneCallback = null;
private Drawable resizingRect = null; private Drawable mResizingRect = null;
private Rect resizingBounds = new Rect(); private final Rect mResizingBounds = new Rect();
private float resizeOffsetX = 0; private float mResizeOffsetX = 0;
private float resizeOffsetY = 0; private float mResizeOffsetY = 0;
public ClientView(Context context) { public ClientView(Context context) {
super(context); super(context);
@@ -53,48 +53,44 @@ public final class ClientView extends RecyclerView {
} }
private void init() { private void init() {
resizingRect = getContext().getResources().getDrawable(R.drawable.resize_rect); mResizingRect = getContext().getResources().getDrawable(R.drawable.resize_rect, null);
} }
void startResizing(View viewToResize, MotionEvent origin, Consumer<Rect> callback) { void startResizing(View viewToResize, MotionEvent origin, Consumer<Rect> callback) {
isResizing = true; mIsResizing = true;
resizeDoneCallback = callback; mResizeDoneCallback = callback;
viewToResize.getGlobalVisibleRect(resizingBounds); viewToResize.getGlobalVisibleRect(mResizingBounds);
resizingRect.setBounds(resizingBounds); mResizingRect.setBounds(mResizingBounds);
getRootView().getOverlay().add(resizingRect); getRootView().getOverlay().add(mResizingRect);
resizeOffsetX = origin.getRawX() - resizingBounds.right; mResizeOffsetX = origin.getRawX() - mResizingBounds.right;
resizeOffsetY = origin.getRawY() - resizingBounds.top; mResizeOffsetY = origin.getRawY() - mResizingBounds.top;
} }
private void stopResizing() { private void stopResizing() {
if (!isResizing) { if (!mIsResizing) {
return; return;
} }
isResizing = false; mIsResizing = false;
resizeOffsetX = resizeOffsetY = 0; mResizeOffsetX = mResizeOffsetY = 0;
getRootView().getOverlay().clear(); getRootView().getOverlay().clear();
if (resizeDoneCallback != null) { if (mResizeDoneCallback != null) {
resizeDoneCallback.accept(resizingBounds); mResizeDoneCallback.accept(mResizingBounds);
resizeDoneCallback = null; mResizeDoneCallback = null;
} }
} }
@Override @Override
public boolean dispatchTouchEvent(MotionEvent ev) { public boolean dispatchTouchEvent(MotionEvent ev) {
if (!isResizing) { if (!mIsResizing) {
return super.dispatchTouchEvent(ev); return super.dispatchTouchEvent(ev);
} }
switch (ev.getAction()) { switch (ev.getAction()) {
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP -> stopResizing();
stopResizing(); case MotionEvent.ACTION_MOVE -> {
break; mResizingBounds.right = (int) (ev.getRawX() - mResizeOffsetX);
case MotionEvent.ACTION_MOVE: mResizingBounds.top = (int) (ev.getRawY() - mResizeOffsetY);
resizingBounds.right = (int) (ev.getRawX() - resizeOffsetX); mResizingRect.setBounds(mResizingBounds);
resizingBounds.top = (int) (ev.getRawY() - resizeOffsetY); }
resizingRect.setBounds(resizingBounds);
break;
default:
break;
} }
return true; return true;
} }

View File

@@ -30,6 +30,7 @@ import android.view.ViewGroup;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ViewHolder; import androidx.recyclerview.widget.RecyclerView.ViewHolder;
@@ -46,34 +47,35 @@ import java.util.concurrent.atomic.AtomicInteger;
final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> { final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
private static final String TAG = "VdmClient"; private static final String TAG = "VdmClient";
private static final AtomicInteger nextDisplayIndex = new AtomicInteger(1); private static final AtomicInteger sNextDisplayIndex = new AtomicInteger(1);
// Simple list of all active displays. // Simple list of all active displays.
private final List<RemoteDisplay> displayRepository = private final List<RemoteDisplay> mDisplayRepository =
Collections.synchronizedList(new ArrayList<>()); Collections.synchronizedList(new ArrayList<>());
private final RemoteIo remoteIo; private final RemoteIo mRemoteIo;
private final ClientView recyclerView; private final ClientView mRecyclerView;
private final InputManager inputManager; private final InputManager mInputManager;
DisplayAdapter(ClientView recyclerView, RemoteIo remoteIo, InputManager inputManager) { DisplayAdapter(ClientView recyclerView, RemoteIo remoteIo, InputManager inputManager) {
this.recyclerView = recyclerView; mRecyclerView = recyclerView;
this.remoteIo = remoteIo; mRemoteIo = remoteIo;
this.inputManager = inputManager; mInputManager = inputManager;
setHasStableIds(true); setHasStableIds(true);
} }
void addDisplay(boolean homeSupported) { void addDisplay(boolean homeSupported) {
Log.i(TAG, "Adding display " + nextDisplayIndex); Log.i(TAG, "Adding display " + sNextDisplayIndex);
displayRepository.add(new RemoteDisplay(nextDisplayIndex.getAndIncrement(), homeSupported)); mDisplayRepository.add(
notifyItemInserted(displayRepository.size() - 1); new RemoteDisplay(sNextDisplayIndex.getAndIncrement(), homeSupported));
notifyItemInserted(mDisplayRepository.size() - 1);
} }
void removeDisplay(int displayId) { void removeDisplay(int displayId) {
Log.i(TAG, "Removing display " + displayId); Log.i(TAG, "Removing display " + displayId);
for (int i = 0; i < displayRepository.size(); ++i) { for (int i = 0; i < mDisplayRepository.size(); ++i) {
if (displayId == displayRepository.get(i).getDisplayId()) { if (displayId == mDisplayRepository.get(i).getDisplayId()) {
displayRepository.remove(i); mDisplayRepository.remove(i);
notifyItemRemoved(i); notifyItemRemoved(i);
break; break;
} }
@@ -97,24 +99,25 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
void clearDisplays() { void clearDisplays() {
Log.i(TAG, "Clearing all displays"); Log.i(TAG, "Clearing all displays");
int size = displayRepository.size(); int size = mDisplayRepository.size();
displayRepository.clear(); mDisplayRepository.clear();
notifyItemRangeRemoved(0, size); notifyItemRangeRemoved(0, size);
} }
private DisplayHolder getDisplayHolder(int displayId) { private DisplayHolder getDisplayHolder(int displayId) {
for (int i = 0; i < displayRepository.size(); ++i) { for (int i = 0; i < mDisplayRepository.size(); ++i) {
if (displayId == displayRepository.get(i).getDisplayId()) { if (displayId == mDisplayRepository.get(i).getDisplayId()) {
return (DisplayHolder) recyclerView.findViewHolderForAdapterPosition(i); return (DisplayHolder) mRecyclerView.findViewHolderForAdapterPosition(i);
} }
} }
return null; return null;
} }
@NonNull
@Override @Override
public DisplayHolder onCreateViewHolder(ViewGroup parent, int viewType) { public DisplayHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Disable recycling so layout changes are not present in new displays. // Disable recycling so layout changes are not present in new displays.
recyclerView.getRecycledViewPool().setMaxRecycledViews(viewType, 0); mRecyclerView.getRecycledViewPool().setMaxRecycledViews(viewType, 0);
View view = View view =
LayoutInflater.from(parent.getContext()) LayoutInflater.from(parent.getContext())
.inflate(R.layout.display_fragment, parent, false); .inflate(R.layout.display_fragment, parent, false);
@@ -133,12 +136,12 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
@Override @Override
public long getItemId(int position) { public long getItemId(int position) {
return displayRepository.get(position).getDisplayId(); return mDisplayRepository.get(position).getDisplayId();
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return displayRepository.size(); return mDisplayRepository.size();
} }
public class DisplayHolder extends ViewHolder { public class DisplayHolder extends ViewHolder {
@@ -216,8 +219,8 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
void close() { void close() {
if (displayController != null) { if (displayController != null) {
Log.i(TAG, "Closing DisplayHolder for display " + displayId); Log.i(TAG, "Closing DisplayHolder for display " + displayId);
inputManager.removeFocusListener(focusListener); mInputManager.removeFocusListener(focusListener);
inputManager.removeFocusableDisplay(displayId); mInputManager.removeFocusableDisplay(displayId);
displayController.close(); displayController.close();
displayController = null; displayController = null;
} }
@@ -225,7 +228,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
void onBind(int position) { void onBind(int position) {
RemoteDisplay remoteDisplay = displayRepository.get(position); RemoteDisplay remoteDisplay = mDisplayRepository.get(position);
displayId = remoteDisplay.getDisplayId(); displayId = remoteDisplay.getDisplayId();
Log.v( Log.v(
TAG, TAG,
@@ -244,9 +247,9 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
displayFocusIndicator.setBackground(null); displayFocusIndicator.setBackground(null);
} }
}; };
inputManager.addFocusListener(focusListener); mInputManager.addFocusListener(focusListener);
displayController = new DisplayController(displayId, remoteIo); displayController = new DisplayController(displayId, mRemoteIo);
Log.v(TAG, "Creating new DisplayController for display " + displayId); Log.v(TAG, "Creating new DisplayController for display " + displayId);
setDisplayTitle(""); setDisplayTitle("");
@@ -256,12 +259,12 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
v -> ((DisplayAdapter) getBindingAdapter()).removeDisplay(displayId)); v -> ((DisplayAdapter) getBindingAdapter()).removeDisplay(displayId));
View backButton = itemView.findViewById(R.id.display_back); View backButton = itemView.findViewById(R.id.display_back);
backButton.setOnClickListener(v -> inputManager.sendBack(displayId)); backButton.setOnClickListener(v -> mInputManager.sendBack(displayId));
View homeButton = itemView.findViewById(R.id.display_home); View homeButton = itemView.findViewById(R.id.display_home);
if (remoteDisplay.isHomeSupported()) { if (remoteDisplay.isHomeSupported()) {
homeButton.setVisibility(View.VISIBLE); homeButton.setVisibility(View.VISIBLE);
homeButton.setOnClickListener(v -> inputManager.sendHome(displayId)); homeButton.setOnClickListener(v -> mInputManager.sendHome(displayId));
} else { } else {
homeButton.setVisibility(View.GONE); homeButton.setVisibility(View.GONE);
} }
@@ -283,7 +286,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
resizeButton.setOnTouchListener( resizeButton.setOnTouchListener(
(v, event) -> { (v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getAction() == MotionEvent.ACTION_DOWN) {
recyclerView.startResizing( mRecyclerView.startResizing(
textureView, event, DisplayHolder.this::resizeDisplay); textureView, event, DisplayHolder.this::resizeDisplay);
return true; return true;
} }
@@ -294,7 +297,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
(v, event) -> { (v, event) -> {
if (event.getDevice().supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) { if (event.getDevice().supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
textureView.getParent().requestDisallowInterceptTouchEvent(true); textureView.getParent().requestDisallowInterceptTouchEvent(true);
inputManager.sendInputEvent( mInputManager.sendInputEvent(
InputDeviceType.DEVICE_TYPE_TOUCHSCREEN, event, displayId); InputDeviceType.DEVICE_TYPE_TOUCHSCREEN, event, displayId);
} }
return true; return true;
@@ -302,19 +305,19 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
textureView.setSurfaceTextureListener( textureView.setSurfaceTextureListener(
new TextureView.SurfaceTextureListener() { new TextureView.SurfaceTextureListener() {
@Override @Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {} public void onSurfaceTextureUpdated(@NonNull SurfaceTexture texture) {}
@Override @Override
public void onSurfaceTextureAvailable( public void onSurfaceTextureAvailable(
SurfaceTexture texture, int width, int height) { @NonNull SurfaceTexture texture, int width, int height) {
Log.v(TAG, "Setting surface for display " + displayId); Log.v(TAG, "Setting surface for display " + displayId);
inputManager.addFocusableDisplay(displayId); mInputManager.addFocusableDisplay(displayId);
surface = new Surface(texture); surface = new Surface(texture);
displayController.setSurface(surface, width, height); displayController.setSurface(surface, width, height);
} }
@Override @Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) { public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture texture) {
Log.v(TAG, "onSurfaceTextureDestroyed for display " + displayId); Log.v(TAG, "onSurfaceTextureDestroyed for display " + displayId);
if (displayController != null) { if (displayController != null) {
displayController.pause(); displayController.pause();
@@ -324,7 +327,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
@Override @Override
public void onSurfaceTextureSizeChanged( public void onSurfaceTextureSizeChanged(
SurfaceTexture texture, int width, int height) { @NonNull SurfaceTexture texture, int width, int height) {
Log.v(TAG, "onSurfaceTextureSizeChanged for display " + displayId); Log.v(TAG, "onSurfaceTextureSizeChanged for display " + displayId);
textureView.setRotation(0); textureView.setRotation(0);
rotateButton.setEnabled(true); rotateButton.setEnabled(true);
@@ -336,7 +339,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|| !event.getDevice().supportsSource(InputDevice.SOURCE_MOUSE)) { || !event.getDevice().supportsSource(InputDevice.SOURCE_MOUSE)) {
return false; return false;
} }
inputManager.sendInputEventToFocusedDisplay( mInputManager.sendInputEventToFocusedDisplay(
InputDeviceType.DEVICE_TYPE_MOUSE, event); InputDeviceType.DEVICE_TYPE_MOUSE, event);
return true; return true;
}); });
@@ -345,20 +348,20 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
private static class RemoteDisplay { private static class RemoteDisplay {
// Local ID, not corresponding to the displayId of the relevant Display on the host device. // Local ID, not corresponding to the displayId of the relevant Display on the host device.
private final int displayId; private final int mDisplayId;
private final boolean homeSupported; private final boolean mHomeSupported;
RemoteDisplay(int displayId, boolean homeSupported) { RemoteDisplay(int displayId, boolean homeSupported) {
this.displayId = displayId; mDisplayId = displayId;
this.homeSupported = homeSupported; mHomeSupported = homeSupported;
} }
int getDisplayId() { int getDisplayId() {
return displayId; return mDisplayId;
} }
boolean isHomeSupported() { boolean isHomeSupported() {
return homeSupported; return mHomeSupported;
} }
} }
} }

View File

@@ -27,71 +27,71 @@ import com.example.android.vdmdemo.common.VideoManager;
final class DisplayController { final class DisplayController {
private static final int DPI = 300; private static final int DPI = 300;
private final int displayId; private final int mDisplayId;
private final RemoteIo remoteIo; private final RemoteIo mRemoteIo;
private VideoManager videoManager = null; private VideoManager mVideoManager = null;
private int dpi = DPI; private int mDpi = DPI;
private RemoteEvent displayCapabilities; private RemoteEvent mDisplayCapabilities;
DisplayController(int displayId, RemoteIo remoteIo) { DisplayController(int displayId, RemoteIo remoteIo) {
this.displayId = displayId; mDisplayId = displayId;
this.remoteIo = remoteIo; mRemoteIo = remoteIo;
} }
void setDpi(int dpi) { void setDpi(int dpi) {
this.dpi = dpi; mDpi = dpi;
} }
int getDpi() { int getDpi() {
return dpi; return mDpi;
} }
void close() { void close() {
remoteIo.sendMessage( mRemoteIo.sendMessage(
RemoteEvent.newBuilder() RemoteEvent.newBuilder()
.setDisplayId(displayId) .setDisplayId(mDisplayId)
.setStopStreaming(StopStreaming.newBuilder()) .setStopStreaming(StopStreaming.newBuilder())
.build()); .build());
if (videoManager != null) { if (mVideoManager != null) {
videoManager.stop(); mVideoManager.stop();
} }
} }
void pause() { void pause() {
if (videoManager == null) { if (mVideoManager == null) {
return; return;
} }
videoManager.stop(); mVideoManager.stop();
videoManager = null; mVideoManager = null;
remoteIo.sendMessage( mRemoteIo.sendMessage(
RemoteEvent.newBuilder() RemoteEvent.newBuilder()
.setDisplayId(displayId) .setDisplayId(mDisplayId)
.setStopStreaming(StopStreaming.newBuilder().setPause(true)) .setStopStreaming(StopStreaming.newBuilder().setPause(true))
.build()); .build());
} }
void sendDisplayCapabilities() { void sendDisplayCapabilities() {
remoteIo.sendMessage(displayCapabilities); mRemoteIo.sendMessage(mDisplayCapabilities);
} }
void setSurface(Surface surface, int width, int height) { void setSurface(Surface surface, int width, int height) {
if (videoManager != null) { if (mVideoManager != null) {
videoManager.stop(); mVideoManager.stop();
} }
videoManager = VideoManager.createDecoder(displayId, remoteIo); mVideoManager = VideoManager.createDecoder(mDisplayId, mRemoteIo);
videoManager.startDecoding(surface, width, height); mVideoManager.startDecoding(surface, width, height);
displayCapabilities = mDisplayCapabilities =
RemoteEvent.newBuilder() RemoteEvent.newBuilder()
.setDisplayId(displayId) .setDisplayId(mDisplayId)
.setDisplayCapabilities( .setDisplayCapabilities(
DisplayCapabilities.newBuilder() DisplayCapabilities.newBuilder()
.setViewportWidth(width) .setViewportWidth(width)
.setViewportHeight(height) .setViewportHeight(height)
.setDensityDpi(dpi)) .setDensityDpi(mDpi))
.build(); .build();
sendDisplayCapabilities(); sendDisplayCapabilities();
} }

View File

@@ -43,7 +43,7 @@ public final class DpadFragment extends Hilt_DpadFragment {
R.id.dpad_center, R.id.dpad_down, R.id.dpad_left, R.id.dpad_up, R.id.dpad_right R.id.dpad_center, R.id.dpad_down, R.id.dpad_left, R.id.dpad_up, R.id.dpad_right
}; };
@Inject InputManager inputManager; @Inject InputManager mInputManager;
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
@@ -87,7 +87,7 @@ public final class DpadFragment extends Hilt_DpadFragment {
Log.w(TAG, "onDpadButtonClick: Method called from a non Dpad button"); Log.w(TAG, "onDpadButtonClick: Method called from a non Dpad button");
return false; return false;
} }
inputManager.sendInputEventToFocusedDisplay( mInputManager.sendInputEventToFocusedDisplay(
InputDeviceType.DEVICE_TYPE_DPAD, InputDeviceType.DEVICE_TYPE_DPAD,
new KeyEvent( new KeyEvent(
/* downTime= */ System.currentTimeMillis(), /* downTime= */ System.currentTimeMillis(),

View File

@@ -27,6 +27,7 @@ import android.view.Surface;
import android.view.TextureView; import android.view.TextureView;
import androidx.activity.OnBackPressedCallback; import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat; import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat; import androidx.core.view.WindowInsetsCompat;
@@ -48,25 +49,22 @@ import javax.inject.Inject;
*/ */
@AndroidEntryPoint(AppCompatActivity.class) @AndroidEntryPoint(AppCompatActivity.class)
public class ImmersiveActivity extends Hilt_ImmersiveActivity { public class ImmersiveActivity extends Hilt_ImmersiveActivity {
private static final String TAG = "VdmImmersiveActivity";
// Approximately, see // Approximately, see
// https://developer.android.com/reference/android/util/DisplayMetrics#density // https://developer.android.com/reference/android/util/DisplayMetrics#density
private static final float DIP_TO_DPI = 160f; private static final float DIP_TO_DPI = 160f;
@Inject ConnectionManager connectionManager; @Inject ConnectionManager mConnectionManager;
@Inject RemoteIo remoteIo; @Inject RemoteIo mRemoteIo;
@Inject VirtualSensorController sensorController; @Inject VirtualSensorController mSensorController;
@Inject AudioPlayer audioPlayer; @Inject AudioPlayer mAudioPlayer;
@Inject InputManager inputManager; @Inject InputManager mInputManager;
private DisplayController displayController; private DisplayController mDisplayController;
private final Consumer<RemoteEvent> remoteEventConsumer = this::processRemoteEvent; private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
private final ConnectionManager.ConnectionCallback connectionCallback = private final ConnectionManager.ConnectionCallback mConnectionCallback =
new ConnectionManager.ConnectionCallback() { new ConnectionManager.ConnectionCallback() {
@Override
public void onConnected(String remoteDeviceName) {}
@Override @Override
public void onDisconnected() { public void onDisconnected() {
@@ -91,20 +89,20 @@ public class ImmersiveActivity extends Hilt_ImmersiveActivity {
new OnBackPressedCallback(true) { new OnBackPressedCallback(true) {
@Override @Override
public void handleOnBackPressed() { public void handleOnBackPressed() {
inputManager.sendBack(DEFAULT_DISPLAY); mInputManager.sendBack(DEFAULT_DISPLAY);
} }
}; };
getOnBackPressedDispatcher().addCallback(this, callback); getOnBackPressedDispatcher().addCallback(this, callback);
displayController = new DisplayController(DEFAULT_DISPLAY, remoteIo); mDisplayController = new DisplayController(DEFAULT_DISPLAY, mRemoteIo);
displayController.setDpi((int) (getResources().getDisplayMetrics().density * DIP_TO_DPI)); mDisplayController.setDpi((int) (getResources().getDisplayMetrics().density * DIP_TO_DPI));
TextureView textureView = findViewById(R.id.immersive_surface_view); TextureView textureView = findViewById(R.id.immersive_surface_view);
textureView.setOnTouchListener( textureView.setOnTouchListener(
(v, event) -> { (v, event) -> {
if (event.getDevice().supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) { if (event.getDevice().supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
textureView.getParent().requestDisallowInterceptTouchEvent(true); textureView.getParent().requestDisallowInterceptTouchEvent(true);
inputManager.sendInputEvent( mInputManager.sendInputEvent(
InputDeviceType.DEVICE_TYPE_TOUCHSCREEN, event, DEFAULT_DISPLAY); InputDeviceType.DEVICE_TYPE_TOUCHSCREEN, event, DEFAULT_DISPLAY);
} }
return true; return true;
@@ -112,53 +110,53 @@ public class ImmersiveActivity extends Hilt_ImmersiveActivity {
textureView.setSurfaceTextureListener( textureView.setSurfaceTextureListener(
new TextureView.SurfaceTextureListener() { new TextureView.SurfaceTextureListener() {
@Override @Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {} public void onSurfaceTextureUpdated(@NonNull SurfaceTexture texture) {}
@Override @Override
public void onSurfaceTextureAvailable( public void onSurfaceTextureAvailable(
SurfaceTexture texture, int width, int height) { @NonNull SurfaceTexture texture, int width, int height) {
displayController.setSurface(new Surface(texture), width, height); mDisplayController.setSurface(new Surface(texture), width, height);
} }
@Override @Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) { public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture texture) {
return true; return true;
} }
@Override @Override
public void onSurfaceTextureSizeChanged( public void onSurfaceTextureSizeChanged(
SurfaceTexture texture, int width, int height) {} @NonNull SurfaceTexture texture, int width, int height) {}
}); });
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
connectionManager.addConnectionCallback(connectionCallback); mConnectionManager.addConnectionCallback(mConnectionCallback);
remoteIo.addMessageConsumer(audioPlayer); mRemoteIo.addMessageConsumer(mAudioPlayer);
remoteIo.addMessageConsumer(remoteEventConsumer); mRemoteIo.addMessageConsumer(mRemoteEventConsumer);
} }
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
connectionManager.removeConnectionCallback(connectionCallback); mConnectionManager.removeConnectionCallback(mConnectionCallback);
remoteIo.removeMessageConsumer(audioPlayer); mRemoteIo.removeMessageConsumer(mAudioPlayer);
remoteIo.removeMessageConsumer(remoteEventConsumer); mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
displayController.close(); mDisplayController.close();
sensorController.close(); mSensorController.close();
} }
private void processRemoteEvent(RemoteEvent event) { private void processRemoteEvent(RemoteEvent event) {
if (event.hasStopStreaming() && !event.getStopStreaming().getPause()) { if (event.hasStopStreaming() && !event.getStopStreaming().getPause()) {
finish(); finish();
} else if (event.hasStartStreaming()) { } else if (event.hasStartStreaming()) {
displayController.sendDisplayCapabilities(); mDisplayController.sendDisplayCapabilities();
} }
} }
@@ -166,14 +164,17 @@ public class ImmersiveActivity extends Hilt_ImmersiveActivity {
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
int keyCode = event.getKeyCode(); int keyCode = event.getKeyCode();
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_UP -> {
inputManager.sendHome(DEFAULT_DISPLAY); mInputManager.sendHome(DEFAULT_DISPLAY);
return true; return true;
case KeyEvent.KEYCODE_VOLUME_DOWN: }
case KeyEvent.KEYCODE_VOLUME_DOWN -> {
finish(); finish();
return true; return true;
default: }
default -> {
return super.dispatchKeyEvent(event); return super.dispatchKeyEvent(event);
} }
} }
} }
}

View File

@@ -47,57 +47,57 @@ import javax.inject.Singleton;
final class InputManager { final class InputManager {
private static final String TAG = "InputManager"; private static final String TAG = "InputManager";
private final RemoteIo remoteIo; private final RemoteIo mRemoteIo;
private final Settings settings; private final Settings mSettings;
private final Object lock = new Object(); private final Object mLock = new Object();
@GuardedBy("lock") @GuardedBy("mLock")
private int focusedDisplayId = Display.INVALID_DISPLAY; private int mFocusedDisplayId = Display.INVALID_DISPLAY;
@GuardedBy("lock") @GuardedBy("mLock")
private boolean isTrackingFocus = false; private boolean mIsTrackingFocus = false;
interface FocusListener { interface FocusListener {
void onFocusChange(int focusedDisplayId); void onFocusChange(int focusedDisplayId);
} }
@GuardedBy("lock") @GuardedBy("mLock")
private final List<FocusListener> focusListeners = new ArrayList<>(); private final List<FocusListener> mFocusListeners = new ArrayList<>();
@GuardedBy("lock") @GuardedBy("mLock")
private final Set<Integer> focusableDisplays = new HashSet<>(); private final Set<Integer> mFocusableDisplays = new HashSet<>();
@Inject @Inject
InputManager(RemoteIo remoteIo, Settings settings) { InputManager(RemoteIo remoteIo, Settings settings) {
this.remoteIo = remoteIo; mRemoteIo = remoteIo;
this.settings = settings; mSettings = settings;
} }
void addFocusListener(FocusListener focusListener) { void addFocusListener(FocusListener focusListener) {
synchronized (lock) { synchronized (mLock) {
focusListeners.add(focusListener); mFocusListeners.add(focusListener);
} }
} }
void removeFocusListener(FocusListener focusListener) { void removeFocusListener(FocusListener focusListener) {
synchronized (lock) { synchronized (mLock) {
focusListeners.remove(focusListener); mFocusListeners.remove(focusListener);
} }
} }
void addFocusableDisplay(int displayId) { void addFocusableDisplay(int displayId) {
synchronized (lock) { synchronized (mLock) {
if (focusableDisplays.add(displayId)) { if (mFocusableDisplays.add(displayId)) {
setFocusedDisplayId(displayId); setFocusedDisplayId(displayId);
} }
} }
} }
void removeFocusableDisplay(int displayId) { void removeFocusableDisplay(int displayId) {
synchronized (lock) { synchronized (mLock) {
focusableDisplays.remove(Integer.valueOf(displayId)); mFocusableDisplays.remove(displayId);
if (displayId == focusedDisplayId) { if (displayId == mFocusedDisplayId) {
setFocusedDisplayId(updateFocusedDisplayId()); setFocusedDisplayId(updateFocusedDisplayId());
} }
} }
@@ -105,21 +105,21 @@ final class InputManager {
void updateFocusTracking() { void updateFocusTracking() {
boolean shouldTrackFocus = boolean shouldTrackFocus =
settings.dpadEnabled mSettings.dpadEnabled
|| settings.navTouchpadEnabled || mSettings.navTouchpadEnabled
|| settings.externalKeyboardEnabled || mSettings.externalKeyboardEnabled
|| settings.externalMouseEnabled; || mSettings.externalMouseEnabled;
List<FocusListener> listenersToNotify = Collections.emptyList(); final List<FocusListener> listenersToNotify;
int focusedDisplayIdToNotify = Display.INVALID_DISPLAY; int focusedDisplayIdToNotify = Display.INVALID_DISPLAY;
synchronized (lock) { synchronized (mLock) {
if (shouldTrackFocus != isTrackingFocus) { if (shouldTrackFocus != mIsTrackingFocus) {
isTrackingFocus = shouldTrackFocus; mIsTrackingFocus = shouldTrackFocus;
} }
if (isTrackingFocus) { if (mIsTrackingFocus) {
focusedDisplayIdToNotify = focusedDisplayId; focusedDisplayIdToNotify = mFocusedDisplayId;
} }
listenersToNotify = new ArrayList<>(focusListeners); listenersToNotify = new ArrayList<>(mFocusListeners);
} }
for (FocusListener focusListener : listenersToNotify) { for (FocusListener focusListener : listenersToNotify) {
focusListener.onFocusChange(focusedDisplayIdToNotify); focusListener.onFocusChange(focusedDisplayIdToNotify);
@@ -152,30 +152,30 @@ final class InputManager {
*/ */
public void sendInputEventToFocusedDisplay(InputDeviceType deviceType, InputEvent inputEvent) { public void sendInputEventToFocusedDisplay(InputDeviceType deviceType, InputEvent inputEvent) {
int targetDisplay; int targetDisplay;
synchronized (lock) { synchronized (mLock) {
if (!isTrackingFocus || focusedDisplayId == Display.INVALID_DISPLAY) { if (!mIsTrackingFocus || mFocusedDisplayId == Display.INVALID_DISPLAY) {
return; return;
} }
targetDisplay = focusedDisplayId; targetDisplay = mFocusedDisplayId;
} }
switch (deviceType) { switch (deviceType) {
case DEVICE_TYPE_NAVIGATION_TOUCHPAD: case DEVICE_TYPE_NAVIGATION_TOUCHPAD:
if (!settings.navTouchpadEnabled) { if (!mSettings.navTouchpadEnabled) {
return; return;
} }
break; break;
case DEVICE_TYPE_DPAD: case DEVICE_TYPE_DPAD:
if (!settings.dpadEnabled) { if (!mSettings.dpadEnabled) {
return; return;
} }
break; break;
case DEVICE_TYPE_MOUSE: case DEVICE_TYPE_MOUSE:
if (!settings.externalMouseEnabled) { if (!mSettings.externalMouseEnabled) {
return; return;
} }
break; break;
case DEVICE_TYPE_KEYBOARD: case DEVICE_TYPE_KEYBOARD:
if (!settings.externalKeyboardEnabled) { if (!mSettings.externalKeyboardEnabled) {
return; return;
} }
break; break;
@@ -206,7 +206,7 @@ final class InputManager {
void sendHome(int displayId) { void sendHome(int displayId) {
setFocusedDisplayId(displayId); setFocusedDisplayId(displayId);
remoteIo.sendMessage( mRemoteIo.sendMessage(
RemoteEvent.newBuilder() RemoteEvent.newBuilder()
.setDisplayId(displayId) .setDisplayId(displayId)
.setHomeEvent(RemoteHomeEvent.newBuilder()) .setHomeEvent(RemoteHomeEvent.newBuilder())
@@ -296,7 +296,7 @@ final class InputManager {
} }
private void sendInputEvent(RemoteInputEvent inputEvent, int displayId) { private void sendInputEvent(RemoteInputEvent inputEvent, int displayId) {
remoteIo.sendMessage( mRemoteIo.sendMessage(
RemoteEvent.newBuilder().setDisplayId(displayId).setInputEvent(inputEvent).build()); RemoteEvent.newBuilder().setDisplayId(displayId).setInputEvent(inputEvent).build());
} }
@@ -305,21 +305,21 @@ final class InputManager {
} }
private int updateFocusedDisplayId() { private int updateFocusedDisplayId() {
synchronized (lock) { synchronized (mLock) {
if (focusableDisplays.contains(focusedDisplayId)) { if (mFocusableDisplays.contains(mFocusedDisplayId)) {
return focusedDisplayId; return mFocusedDisplayId;
} }
return Iterables.getFirst(focusableDisplays, Display.INVALID_DISPLAY); return Iterables.getFirst(mFocusableDisplays, Display.INVALID_DISPLAY);
} }
} }
private void setFocusedDisplayId(int displayId) { private void setFocusedDisplayId(int displayId) {
List<FocusListener> listenersToNotify = Collections.emptyList(); List<FocusListener> listenersToNotify = Collections.emptyList();
synchronized (lock) { synchronized (mLock) {
if (displayId != focusedDisplayId) { if (displayId != mFocusedDisplayId) {
focusedDisplayId = displayId; mFocusedDisplayId = displayId;
if (isTrackingFocus) { if (mIsTrackingFocus) {
listenersToNotify = new ArrayList<>(focusListeners); listenersToNotify = new ArrayList<>(mFocusListeners);
} }
} }
} }

View File

@@ -49,45 +49,45 @@ import javax.inject.Inject;
@AndroidEntryPoint(AppCompatActivity.class) @AndroidEntryPoint(AppCompatActivity.class)
public class MainActivity extends Hilt_MainActivity { public class MainActivity extends Hilt_MainActivity {
@Inject RemoteIo remoteIo; @Inject RemoteIo mRemoteIo;
@Inject ConnectionManager connectionManager; @Inject ConnectionManager mConnectionManager;
@Inject InputManager inputManager; @Inject InputManager mInputManager;
@Inject VirtualSensorController sensorController; @Inject VirtualSensorController mSensorController;
@Inject AudioPlayer audioPlayer; @Inject AudioPlayer mAudioPlayer;
@Inject Settings settings; @Inject Settings mSettings;
private final Consumer<RemoteEvent> remoteEventConsumer = this::processRemoteEvent; private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
private DisplayAdapter displayAdapter; private DisplayAdapter mDisplayAdapter;
private final InputManager.FocusListener focusListener = this::onDisplayFocusChange; private final InputManager.FocusListener mFocusListener = this::onDisplayFocusChange;
private final ConnectionManager.ConnectionCallback connectionCallback = private final ConnectionManager.ConnectionCallback mConnectionCallback =
new ConnectionManager.ConnectionCallback() { new ConnectionManager.ConnectionCallback() {
@Override @Override
public void onConnecting(String remoteDeviceName) { public void onConnecting(String remoteDeviceName) {
connectionManager.stopAdvertising(); mConnectionManager.stopAdvertising();
} }
@Override @Override
public void onConnected(String remoteDeviceName) { public void onConnected(String remoteDeviceName) {
remoteIo.sendMessage( mRemoteIo.sendMessage(
RemoteEvent.newBuilder() RemoteEvent.newBuilder()
.setDeviceCapabilities( .setDeviceCapabilities(
DeviceCapabilities.newBuilder() DeviceCapabilities.newBuilder()
.setDeviceName(Build.MODEL) .setDeviceName(Build.MODEL)
.addAllSensorCapabilities( .addAllSensorCapabilities(
(sensorController (mSensorController
.getSensorCapabilities()))) .getSensorCapabilities())))
.build()); .build());
} }
@Override @Override
public void onDisconnected() { public void onDisconnected() {
if (displayAdapter != null) { if (mDisplayAdapter != null) {
runOnUiThread(displayAdapter::clearDisplays); runOnUiThread(mDisplayAdapter::clearDisplays);
} }
connectionManager.startAdvertising(); mConnectionManager.startAdvertising();
} }
}; };
@@ -104,36 +104,36 @@ public class MainActivity extends Hilt_MainActivity {
displaysView.setLayoutManager( displaysView.setLayoutManager(
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)); new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
displaysView.setItemAnimator(null); displaysView.setItemAnimator(null);
displayAdapter = new DisplayAdapter(displaysView, remoteIo, inputManager); mDisplayAdapter = new DisplayAdapter(displaysView, mRemoteIo, mInputManager);
displaysView.setAdapter(displayAdapter); displaysView.setAdapter(mDisplayAdapter);
} }
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
connectionManager.addConnectionCallback(connectionCallback); mConnectionManager.addConnectionCallback(mConnectionCallback);
connectionManager.startAdvertising(); mConnectionManager.startAdvertising();
inputManager.addFocusListener(focusListener); mInputManager.addFocusListener(mFocusListener);
remoteIo.addMessageConsumer(audioPlayer); mRemoteIo.addMessageConsumer(mAudioPlayer);
remoteIo.addMessageConsumer(remoteEventConsumer); mRemoteIo.addMessageConsumer(mRemoteEventConsumer);
} }
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
inputManager.removeFocusListener(focusListener); mInputManager.removeFocusListener(mFocusListener);
connectionManager.removeConnectionCallback(connectionCallback); mConnectionManager.removeConnectionCallback(mConnectionCallback);
connectionManager.stopAdvertising(); mConnectionManager.stopAdvertising();
remoteIo.removeMessageConsumer(remoteEventConsumer); mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
remoteIo.removeMessageConsumer(audioPlayer); mRemoteIo.removeMessageConsumer(mAudioPlayer);
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
displayAdapter.clearDisplays(); mDisplayAdapter.clearDisplays();
connectionManager.disconnect(); mConnectionManager.disconnect();
sensorController.close(); mSensorController.close();
} }
@Override @Override
@@ -142,7 +142,7 @@ public class MainActivity extends Hilt_MainActivity {
|| !event.getDevice().supportsSource(InputDevice.SOURCE_KEYBOARD)) { || !event.getDevice().supportsSource(InputDevice.SOURCE_KEYBOARD)) {
return false; return false;
} }
inputManager.sendInputEventToFocusedDisplay(InputDeviceType.DEVICE_TYPE_KEYBOARD, event); mInputManager.sendInputEventToFocusedDisplay(InputDeviceType.DEVICE_TYPE_KEYBOARD, event);
return true; return true;
} }
@@ -153,18 +153,11 @@ public class MainActivity extends Hilt_MainActivity {
for (int i = 0; i < menu.size(); ++i) { for (int i = 0; i < menu.size(); ++i) {
MenuItem item = menu.getItem(i); MenuItem item = menu.getItem(i);
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.enable_dpad: case R.id.enable_dpad -> item.setChecked(mSettings.dpadEnabled);
item.setChecked(settings.dpadEnabled); case R.id.enable_nav_touchpad -> item.setChecked(mSettings.navTouchpadEnabled);
break; case R.id.enable_external_keyboard -> item.setChecked(
case R.id.enable_nav_touchpad: mSettings.externalKeyboardEnabled);
item.setChecked(settings.navTouchpadEnabled); case R.id.enable_external_mouse -> item.setChecked(mSettings.externalMouseEnabled);
break;
case R.id.enable_external_keyboard:
item.setChecked(settings.externalKeyboardEnabled);
break;
case R.id.enable_external_mouse:
item.setChecked(settings.externalMouseEnabled);
break;
} }
} }
return true; return true;
@@ -175,23 +168,17 @@ public class MainActivity extends Hilt_MainActivity {
item.setChecked(!item.isChecked()); item.setChecked(!item.isChecked());
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.enable_dpad: case R.id.enable_dpad -> mSettings.dpadEnabled = item.isChecked();
settings.dpadEnabled = item.isChecked(); case R.id.enable_nav_touchpad -> mSettings.navTouchpadEnabled = item.isChecked();
break; case R.id.enable_external_keyboard ->
case R.id.enable_nav_touchpad: mSettings.externalKeyboardEnabled = item.isChecked();
settings.navTouchpadEnabled = item.isChecked(); case R.id.enable_external_mouse -> mSettings.externalMouseEnabled = item.isChecked();
break; default -> {
case R.id.enable_external_keyboard:
settings.externalKeyboardEnabled = item.isChecked();
break;
case R.id.enable_external_mouse:
settings.externalMouseEnabled = item.isChecked();
break;
default:
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
}
inputManager.updateFocusTracking(); mInputManager.updateFocusTracking();
return true; return true;
} }
@@ -202,27 +189,27 @@ public class MainActivity extends Hilt_MainActivity {
} else { } else {
runOnUiThread( runOnUiThread(
() -> () ->
displayAdapter.addDisplay( mDisplayAdapter.addDisplay(
event.getStartStreaming().getHomeEnabled())); event.getStartStreaming().getHomeEnabled()));
} }
} else if (event.hasStopStreaming()) { } else if (event.hasStopStreaming()) {
runOnUiThread(() -> displayAdapter.removeDisplay(event.getDisplayId())); runOnUiThread(() -> mDisplayAdapter.removeDisplay(event.getDisplayId()));
} else if (event.hasDisplayRotation()) { } else if (event.hasDisplayRotation()) {
runOnUiThread(() -> displayAdapter.rotateDisplay(event)); runOnUiThread(() -> mDisplayAdapter.rotateDisplay(event));
} else if (event.hasDisplayChangeEvent()) { } else if (event.hasDisplayChangeEvent()) {
runOnUiThread(() -> displayAdapter.processDisplayChange(event)); runOnUiThread(() -> mDisplayAdapter.processDisplayChange(event));
} }
} }
private void onDisplayFocusChange(int displayId) { private void onDisplayFocusChange(int displayId) {
findViewById(R.id.dpad_fragment_container) findViewById(R.id.dpad_fragment_container)
.setVisibility( .setVisibility(
settings.dpadEnabled && displayId != Display.INVALID_DISPLAY mSettings.dpadEnabled && displayId != Display.INVALID_DISPLAY
? View.VISIBLE ? View.VISIBLE
: View.GONE); : View.GONE);
findViewById(R.id.nav_touchpad_fragment_container) findViewById(R.id.nav_touchpad_fragment_container)
.setVisibility( .setVisibility(
settings.navTouchpadEnabled && displayId != Display.INVALID_DISPLAY mSettings.navTouchpadEnabled && displayId != Display.INVALID_DISPLAY
? View.VISIBLE ? View.VISIBLE
: View.GONE); : View.GONE);
} }

View File

@@ -35,7 +35,7 @@ import javax.inject.Inject;
@AndroidEntryPoint(Fragment.class) @AndroidEntryPoint(Fragment.class)
public final class NavTouchpadFragment extends Hilt_NavTouchpadFragment { public final class NavTouchpadFragment extends Hilt_NavTouchpadFragment {
@Inject InputManager inputManager; @Inject InputManager mInputManager;
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
@@ -46,7 +46,7 @@ public final class NavTouchpadFragment extends Hilt_NavTouchpadFragment {
TextView navTouchpad = view.findViewById(R.id.nav_touchpad); TextView navTouchpad = view.findViewById(R.id.nav_touchpad);
navTouchpad.setOnTouchListener( navTouchpad.setOnTouchListener(
(v, event) -> { (v, event) -> {
inputManager.sendInputEventToFocusedDisplay( mInputManager.sendInputEventToFocusedDisplay(
InputDeviceType.DEVICE_TYPE_NAVIGATION_TOUCHPAD, event); InputDeviceType.DEVICE_TYPE_NAVIGATION_TOUCHPAD, event);
return true; return true;
}); });

View File

@@ -22,10 +22,10 @@ import javax.inject.Singleton;
/** Settings known to the VDM Demo Client application */ /** Settings known to the VDM Demo Client application */
@Singleton @Singleton
final class Settings { final class Settings {
boolean dpadEnabled = false; public boolean dpadEnabled = false;
boolean navTouchpadEnabled = false; public boolean navTouchpadEnabled = false;
boolean externalKeyboardEnabled = false; public boolean externalKeyboardEnabled = false;
boolean externalMouseEnabled = false; public boolean externalMouseEnabled = false;
@Inject @Inject
Settings() {} Settings() {}

View File

@@ -43,17 +43,17 @@ import javax.inject.Inject;
@ActivityScoped @ActivityScoped
final class VirtualSensorController implements AutoCloseable { final class VirtualSensorController implements AutoCloseable {
private final RemoteIo remoteIo; private final RemoteIo mRemoteIo;
private final Consumer<RemoteEvent> remoteEventConsumer = this::processRemoteEvent; private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
private final SensorManager sensorManager; private final SensorManager mSensorManager;
private final HandlerThread listenerThread; private final HandlerThread mListenerThread;
private final Handler handler; private final Handler mHandler;
private final SensorEventListener sensorEventListener = private final SensorEventListener sensorEventListener =
new SensorEventListener() { new SensorEventListener() {
@Override @Override
public void onSensorChanged(SensorEvent event) { public void onSensorChanged(SensorEvent event) {
remoteIo.sendMessage( mRemoteIo.sendMessage(
RemoteEvent.newBuilder() RemoteEvent.newBuilder()
.setSensorEvent( .setSensorEvent(
RemoteSensorEvent.newBuilder() RemoteSensorEvent.newBuilder()
@@ -68,25 +68,25 @@ final class VirtualSensorController implements AutoCloseable {
@Inject @Inject
VirtualSensorController(@ApplicationContext Context context, RemoteIo remoteIo) { VirtualSensorController(@ApplicationContext Context context, RemoteIo remoteIo) {
this.sensorManager = context.getSystemService(SensorManager.class); mSensorManager = context.getSystemService(SensorManager.class);
this.remoteIo = remoteIo; mRemoteIo = remoteIo;
listenerThread = new HandlerThread("VirtualSensorListener"); mListenerThread = new HandlerThread("VirtualSensorListener");
listenerThread.start(); mListenerThread.start();
handler = new Handler(listenerThread.getLooper()); mHandler = new Handler(mListenerThread.getLooper());
remoteIo.addMessageConsumer(remoteEventConsumer); remoteIo.addMessageConsumer(mRemoteEventConsumer);
} }
@Override @Override
public void close() { public void close() {
sensorManager.unregisterListener(sensorEventListener); mSensorManager.unregisterListener(sensorEventListener);
listenerThread.quitSafely(); mListenerThread.quitSafely();
remoteIo.removeMessageConsumer(remoteEventConsumer); mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
} }
public List<SensorCapabilities> getSensorCapabilities() { public List<SensorCapabilities> getSensorCapabilities() {
return sensorManager.getSensorList(Sensor.TYPE_ALL).stream() return mSensorManager.getSensorList(Sensor.TYPE_ALL).stream()
.map( .map(
sensor -> sensor ->
SensorCapabilities.newBuilder() SensorCapabilities.newBuilder()
@@ -107,19 +107,19 @@ final class VirtualSensorController implements AutoCloseable {
return; return;
} }
SensorConfiguration config = remoteEvent.getSensorConfiguration(); SensorConfiguration config = remoteEvent.getSensorConfiguration();
Sensor sensor = sensorManager.getDefaultSensor(config.getSensorType()); Sensor sensor = mSensorManager.getDefaultSensor(config.getSensorType());
if (sensor == null) { if (sensor == null) {
return; return;
} }
if (config.getEnabled()) { if (config.getEnabled()) {
sensorManager.registerListener( mSensorManager.registerListener(
sensorEventListener, sensorEventListener,
sensor, sensor,
config.getSamplingPeriodUs(), config.getSamplingPeriodUs(),
config.getBatchReportingLatencyUs(), config.getBatchReportingLatencyUs(),
handler); mHandler);
} else { } else {
sensorManager.unregisterListener(sensorEventListener, sensor); mSensorManager.unregisterListener(sensorEventListener, sensor);
} }
} }
} }