Merge "VDM demo: all repohooks fixed for client/" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
5ea9f410ed
@@ -47,25 +47,25 @@ final class AudioPlayer implements Consumer<RemoteEvent> {
|
||||
SAMPLE_RATE, AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
|
||||
private static final int AUDIOTRACK_BUFFER_SIZE = 4 * MIN_AUDIOTRACK_BUFFER_SIZE;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private AudioTrack audioTrack;
|
||||
private final Object mLock = new Object();
|
||||
private AudioTrack mAudioTrack;
|
||||
|
||||
@Inject
|
||||
AudioPlayer() {}
|
||||
|
||||
private void startPlayback() {
|
||||
synchronized (lock) {
|
||||
if (audioTrack != null) {
|
||||
synchronized (mLock) {
|
||||
if (mAudioTrack != null) {
|
||||
Log.w(TAG, "Received startPlayback command without stopping the playback first");
|
||||
stopPlayback();
|
||||
}
|
||||
audioTrack =
|
||||
mAudioTrack =
|
||||
new AudioTrack.Builder()
|
||||
.setAudioFormat(AUDIO_FORMAT)
|
||||
.setAudioAttributes(AUDIO_ATTRIBUTES)
|
||||
.setBufferSizeInBytes(AUDIOTRACK_BUFFER_SIZE)
|
||||
.build();
|
||||
audioTrack.play();
|
||||
mAudioTrack.play();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,14 +76,14 @@ final class AudioPlayer implements Consumer<RemoteEvent> {
|
||||
return;
|
||||
}
|
||||
int bytesWritten = 0;
|
||||
synchronized (lock) {
|
||||
if (audioTrack == null) {
|
||||
synchronized (mLock) {
|
||||
if (mAudioTrack == null) {
|
||||
Log.e(TAG, "Received audio frame, but audio track was not initialized yet");
|
||||
return;
|
||||
}
|
||||
|
||||
while (bytesToWrite > 0) {
|
||||
int ret = audioTrack.write(data, bytesWritten, bytesToWrite);
|
||||
int ret = mAudioTrack.write(data, bytesWritten, bytesToWrite);
|
||||
if (ret <= 0) {
|
||||
Log.e(TAG, "AudioTrack.write returned error code " + ret);
|
||||
}
|
||||
@@ -94,13 +94,13 @@ final class AudioPlayer implements Consumer<RemoteEvent> {
|
||||
}
|
||||
|
||||
private void stopPlayback() {
|
||||
synchronized (lock) {
|
||||
if (audioTrack == null) {
|
||||
synchronized (mLock) {
|
||||
if (mAudioTrack == null) {
|
||||
Log.w(TAG, "Received stopPlayback command for already stopped playback");
|
||||
} else {
|
||||
audioTrack.stop();
|
||||
audioTrack.release();
|
||||
audioTrack = null;
|
||||
mAudioTrack.stop();
|
||||
mAudioTrack.release();
|
||||
mAudioTrack = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ import java.util.function.Consumer;
|
||||
|
||||
/** Recycler view that can resize a child dynamically. */
|
||||
public final class ClientView extends RecyclerView {
|
||||
private boolean isResizing = false;
|
||||
private Consumer<Rect> resizeDoneCallback = null;
|
||||
private Drawable resizingRect = null;
|
||||
private Rect resizingBounds = new Rect();
|
||||
private float resizeOffsetX = 0;
|
||||
private float resizeOffsetY = 0;
|
||||
private boolean mIsResizing = false;
|
||||
private Consumer<Rect> mResizeDoneCallback = null;
|
||||
private Drawable mResizingRect = null;
|
||||
private final Rect mResizingBounds = new Rect();
|
||||
private float mResizeOffsetX = 0;
|
||||
private float mResizeOffsetY = 0;
|
||||
|
||||
public ClientView(Context context) {
|
||||
super(context);
|
||||
@@ -53,48 +53,44 @@ public final class ClientView extends RecyclerView {
|
||||
}
|
||||
|
||||
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) {
|
||||
isResizing = true;
|
||||
resizeDoneCallback = callback;
|
||||
viewToResize.getGlobalVisibleRect(resizingBounds);
|
||||
resizingRect.setBounds(resizingBounds);
|
||||
getRootView().getOverlay().add(resizingRect);
|
||||
resizeOffsetX = origin.getRawX() - resizingBounds.right;
|
||||
resizeOffsetY = origin.getRawY() - resizingBounds.top;
|
||||
mIsResizing = true;
|
||||
mResizeDoneCallback = callback;
|
||||
viewToResize.getGlobalVisibleRect(mResizingBounds);
|
||||
mResizingRect.setBounds(mResizingBounds);
|
||||
getRootView().getOverlay().add(mResizingRect);
|
||||
mResizeOffsetX = origin.getRawX() - mResizingBounds.right;
|
||||
mResizeOffsetY = origin.getRawY() - mResizingBounds.top;
|
||||
}
|
||||
|
||||
private void stopResizing() {
|
||||
if (!isResizing) {
|
||||
if (!mIsResizing) {
|
||||
return;
|
||||
}
|
||||
isResizing = false;
|
||||
resizeOffsetX = resizeOffsetY = 0;
|
||||
mIsResizing = false;
|
||||
mResizeOffsetX = mResizeOffsetY = 0;
|
||||
getRootView().getOverlay().clear();
|
||||
if (resizeDoneCallback != null) {
|
||||
resizeDoneCallback.accept(resizingBounds);
|
||||
resizeDoneCallback = null;
|
||||
if (mResizeDoneCallback != null) {
|
||||
mResizeDoneCallback.accept(mResizingBounds);
|
||||
mResizeDoneCallback = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent ev) {
|
||||
if (!isResizing) {
|
||||
if (!mIsResizing) {
|
||||
return super.dispatchTouchEvent(ev);
|
||||
}
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
stopResizing();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
resizingBounds.right = (int) (ev.getRawX() - resizeOffsetX);
|
||||
resizingBounds.top = (int) (ev.getRawY() - resizeOffsetY);
|
||||
resizingRect.setBounds(resizingBounds);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case MotionEvent.ACTION_UP -> stopResizing();
|
||||
case MotionEvent.ACTION_MOVE -> {
|
||||
mResizingBounds.right = (int) (ev.getRawX() - mResizeOffsetX);
|
||||
mResizingBounds.top = (int) (ev.getRawY() - mResizeOffsetY);
|
||||
mResizingRect.setBounds(mResizingBounds);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder;
|
||||
|
||||
@@ -46,34 +47,35 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
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.
|
||||
private final List<RemoteDisplay> displayRepository =
|
||||
private final List<RemoteDisplay> mDisplayRepository =
|
||||
Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private final RemoteIo remoteIo;
|
||||
private final ClientView recyclerView;
|
||||
private final InputManager inputManager;
|
||||
private final RemoteIo mRemoteIo;
|
||||
private final ClientView mRecyclerView;
|
||||
private final InputManager mInputManager;
|
||||
|
||||
DisplayAdapter(ClientView recyclerView, RemoteIo remoteIo, InputManager inputManager) {
|
||||
this.recyclerView = recyclerView;
|
||||
this.remoteIo = remoteIo;
|
||||
this.inputManager = inputManager;
|
||||
mRecyclerView = recyclerView;
|
||||
mRemoteIo = remoteIo;
|
||||
mInputManager = inputManager;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
void addDisplay(boolean homeSupported) {
|
||||
Log.i(TAG, "Adding display " + nextDisplayIndex);
|
||||
displayRepository.add(new RemoteDisplay(nextDisplayIndex.getAndIncrement(), homeSupported));
|
||||
notifyItemInserted(displayRepository.size() - 1);
|
||||
Log.i(TAG, "Adding display " + sNextDisplayIndex);
|
||||
mDisplayRepository.add(
|
||||
new RemoteDisplay(sNextDisplayIndex.getAndIncrement(), homeSupported));
|
||||
notifyItemInserted(mDisplayRepository.size() - 1);
|
||||
}
|
||||
|
||||
void removeDisplay(int displayId) {
|
||||
Log.i(TAG, "Removing display " + displayId);
|
||||
for (int i = 0; i < displayRepository.size(); ++i) {
|
||||
if (displayId == displayRepository.get(i).getDisplayId()) {
|
||||
displayRepository.remove(i);
|
||||
for (int i = 0; i < mDisplayRepository.size(); ++i) {
|
||||
if (displayId == mDisplayRepository.get(i).getDisplayId()) {
|
||||
mDisplayRepository.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
break;
|
||||
}
|
||||
@@ -97,24 +99,25 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
|
||||
void clearDisplays() {
|
||||
Log.i(TAG, "Clearing all displays");
|
||||
int size = displayRepository.size();
|
||||
displayRepository.clear();
|
||||
int size = mDisplayRepository.size();
|
||||
mDisplayRepository.clear();
|
||||
notifyItemRangeRemoved(0, size);
|
||||
}
|
||||
|
||||
private DisplayHolder getDisplayHolder(int displayId) {
|
||||
for (int i = 0; i < displayRepository.size(); ++i) {
|
||||
if (displayId == displayRepository.get(i).getDisplayId()) {
|
||||
return (DisplayHolder) recyclerView.findViewHolderForAdapterPosition(i);
|
||||
for (int i = 0; i < mDisplayRepository.size(); ++i) {
|
||||
if (displayId == mDisplayRepository.get(i).getDisplayId()) {
|
||||
return (DisplayHolder) mRecyclerView.findViewHolderForAdapterPosition(i);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DisplayHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
// Disable recycling so layout changes are not present in new displays.
|
||||
recyclerView.getRecycledViewPool().setMaxRecycledViews(viewType, 0);
|
||||
mRecyclerView.getRecycledViewPool().setMaxRecycledViews(viewType, 0);
|
||||
View view =
|
||||
LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.display_fragment, parent, false);
|
||||
@@ -133,12 +136,12 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return displayRepository.get(position).getDisplayId();
|
||||
return mDisplayRepository.get(position).getDisplayId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return displayRepository.size();
|
||||
return mDisplayRepository.size();
|
||||
}
|
||||
|
||||
public class DisplayHolder extends ViewHolder {
|
||||
@@ -216,8 +219,8 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
void close() {
|
||||
if (displayController != null) {
|
||||
Log.i(TAG, "Closing DisplayHolder for display " + displayId);
|
||||
inputManager.removeFocusListener(focusListener);
|
||||
inputManager.removeFocusableDisplay(displayId);
|
||||
mInputManager.removeFocusListener(focusListener);
|
||||
mInputManager.removeFocusableDisplay(displayId);
|
||||
displayController.close();
|
||||
displayController = null;
|
||||
}
|
||||
@@ -225,7 +228,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
void onBind(int position) {
|
||||
RemoteDisplay remoteDisplay = displayRepository.get(position);
|
||||
RemoteDisplay remoteDisplay = mDisplayRepository.get(position);
|
||||
displayId = remoteDisplay.getDisplayId();
|
||||
Log.v(
|
||||
TAG,
|
||||
@@ -244,9 +247,9 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
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);
|
||||
|
||||
setDisplayTitle("");
|
||||
@@ -256,12 +259,12 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
v -> ((DisplayAdapter) getBindingAdapter()).removeDisplay(displayId));
|
||||
|
||||
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);
|
||||
if (remoteDisplay.isHomeSupported()) {
|
||||
homeButton.setVisibility(View.VISIBLE);
|
||||
homeButton.setOnClickListener(v -> inputManager.sendHome(displayId));
|
||||
homeButton.setOnClickListener(v -> mInputManager.sendHome(displayId));
|
||||
} else {
|
||||
homeButton.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -283,7 +286,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
resizeButton.setOnTouchListener(
|
||||
(v, event) -> {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
recyclerView.startResizing(
|
||||
mRecyclerView.startResizing(
|
||||
textureView, event, DisplayHolder.this::resizeDisplay);
|
||||
return true;
|
||||
}
|
||||
@@ -294,7 +297,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
(v, event) -> {
|
||||
if (event.getDevice().supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
|
||||
textureView.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
inputManager.sendInputEvent(
|
||||
mInputManager.sendInputEvent(
|
||||
InputDeviceType.DEVICE_TYPE_TOUCHSCREEN, event, displayId);
|
||||
}
|
||||
return true;
|
||||
@@ -302,19 +305,19 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
textureView.setSurfaceTextureListener(
|
||||
new TextureView.SurfaceTextureListener() {
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) {}
|
||||
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture texture) {}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(
|
||||
SurfaceTexture texture, int width, int height) {
|
||||
@NonNull SurfaceTexture texture, int width, int height) {
|
||||
Log.v(TAG, "Setting surface for display " + displayId);
|
||||
inputManager.addFocusableDisplay(displayId);
|
||||
mInputManager.addFocusableDisplay(displayId);
|
||||
surface = new Surface(texture);
|
||||
displayController.setSurface(surface, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
|
||||
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture texture) {
|
||||
Log.v(TAG, "onSurfaceTextureDestroyed for display " + displayId);
|
||||
if (displayController != null) {
|
||||
displayController.pause();
|
||||
@@ -324,7 +327,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(
|
||||
SurfaceTexture texture, int width, int height) {
|
||||
@NonNull SurfaceTexture texture, int width, int height) {
|
||||
Log.v(TAG, "onSurfaceTextureSizeChanged for display " + displayId);
|
||||
textureView.setRotation(0);
|
||||
rotateButton.setEnabled(true);
|
||||
@@ -336,7 +339,7 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
|| !event.getDevice().supportsSource(InputDevice.SOURCE_MOUSE)) {
|
||||
return false;
|
||||
}
|
||||
inputManager.sendInputEventToFocusedDisplay(
|
||||
mInputManager.sendInputEventToFocusedDisplay(
|
||||
InputDeviceType.DEVICE_TYPE_MOUSE, event);
|
||||
return true;
|
||||
});
|
||||
@@ -345,20 +348,20 @@ final class DisplayAdapter extends RecyclerView.Adapter<DisplayHolder> {
|
||||
|
||||
private static class RemoteDisplay {
|
||||
// Local ID, not corresponding to the displayId of the relevant Display on the host device.
|
||||
private final int displayId;
|
||||
private final boolean homeSupported;
|
||||
private final int mDisplayId;
|
||||
private final boolean mHomeSupported;
|
||||
|
||||
RemoteDisplay(int displayId, boolean homeSupported) {
|
||||
this.displayId = displayId;
|
||||
this.homeSupported = homeSupported;
|
||||
mDisplayId = displayId;
|
||||
mHomeSupported = homeSupported;
|
||||
}
|
||||
|
||||
int getDisplayId() {
|
||||
return displayId;
|
||||
return mDisplayId;
|
||||
}
|
||||
|
||||
boolean isHomeSupported() {
|
||||
return homeSupported;
|
||||
return mHomeSupported;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,71 +27,71 @@ import com.example.android.vdmdemo.common.VideoManager;
|
||||
final class DisplayController {
|
||||
private static final int DPI = 300;
|
||||
|
||||
private final int displayId;
|
||||
private final RemoteIo remoteIo;
|
||||
private final int mDisplayId;
|
||||
private final RemoteIo mRemoteIo;
|
||||
|
||||
private VideoManager videoManager = null;
|
||||
private VideoManager mVideoManager = null;
|
||||
|
||||
private int dpi = DPI;
|
||||
private RemoteEvent displayCapabilities;
|
||||
private int mDpi = DPI;
|
||||
private RemoteEvent mDisplayCapabilities;
|
||||
|
||||
DisplayController(int displayId, RemoteIo remoteIo) {
|
||||
this.displayId = displayId;
|
||||
this.remoteIo = remoteIo;
|
||||
mDisplayId = displayId;
|
||||
mRemoteIo = remoteIo;
|
||||
}
|
||||
|
||||
void setDpi(int dpi) {
|
||||
this.dpi = dpi;
|
||||
mDpi = dpi;
|
||||
}
|
||||
|
||||
int getDpi() {
|
||||
return dpi;
|
||||
return mDpi;
|
||||
}
|
||||
|
||||
void close() {
|
||||
remoteIo.sendMessage(
|
||||
mRemoteIo.sendMessage(
|
||||
RemoteEvent.newBuilder()
|
||||
.setDisplayId(displayId)
|
||||
.setDisplayId(mDisplayId)
|
||||
.setStopStreaming(StopStreaming.newBuilder())
|
||||
.build());
|
||||
|
||||
if (videoManager != null) {
|
||||
videoManager.stop();
|
||||
if (mVideoManager != null) {
|
||||
mVideoManager.stop();
|
||||
}
|
||||
}
|
||||
|
||||
void pause() {
|
||||
if (videoManager == null) {
|
||||
if (mVideoManager == null) {
|
||||
return;
|
||||
}
|
||||
videoManager.stop();
|
||||
videoManager = null;
|
||||
mVideoManager.stop();
|
||||
mVideoManager = null;
|
||||
|
||||
remoteIo.sendMessage(
|
||||
mRemoteIo.sendMessage(
|
||||
RemoteEvent.newBuilder()
|
||||
.setDisplayId(displayId)
|
||||
.setDisplayId(mDisplayId)
|
||||
.setStopStreaming(StopStreaming.newBuilder().setPause(true))
|
||||
.build());
|
||||
}
|
||||
|
||||
void sendDisplayCapabilities() {
|
||||
remoteIo.sendMessage(displayCapabilities);
|
||||
mRemoteIo.sendMessage(mDisplayCapabilities);
|
||||
}
|
||||
|
||||
void setSurface(Surface surface, int width, int height) {
|
||||
if (videoManager != null) {
|
||||
videoManager.stop();
|
||||
if (mVideoManager != null) {
|
||||
mVideoManager.stop();
|
||||
}
|
||||
videoManager = VideoManager.createDecoder(displayId, remoteIo);
|
||||
videoManager.startDecoding(surface, width, height);
|
||||
displayCapabilities =
|
||||
mVideoManager = VideoManager.createDecoder(mDisplayId, mRemoteIo);
|
||||
mVideoManager.startDecoding(surface, width, height);
|
||||
mDisplayCapabilities =
|
||||
RemoteEvent.newBuilder()
|
||||
.setDisplayId(displayId)
|
||||
.setDisplayId(mDisplayId)
|
||||
.setDisplayCapabilities(
|
||||
DisplayCapabilities.newBuilder()
|
||||
.setViewportWidth(width)
|
||||
.setViewportHeight(height)
|
||||
.setDensityDpi(dpi))
|
||||
.setDensityDpi(mDpi))
|
||||
.build();
|
||||
sendDisplayCapabilities();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@Inject InputManager inputManager;
|
||||
@Inject InputManager mInputManager;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
@@ -87,7 +87,7 @@ public final class DpadFragment extends Hilt_DpadFragment {
|
||||
Log.w(TAG, "onDpadButtonClick: Method called from a non Dpad button");
|
||||
return false;
|
||||
}
|
||||
inputManager.sendInputEventToFocusedDisplay(
|
||||
mInputManager.sendInputEventToFocusedDisplay(
|
||||
InputDeviceType.DEVICE_TYPE_DPAD,
|
||||
new KeyEvent(
|
||||
/* downTime= */ System.currentTimeMillis(),
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.view.Surface;
|
||||
import android.view.TextureView;
|
||||
|
||||
import androidx.activity.OnBackPressedCallback;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.view.WindowCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
@@ -48,25 +49,22 @@ import javax.inject.Inject;
|
||||
*/
|
||||
@AndroidEntryPoint(AppCompatActivity.class)
|
||||
public class ImmersiveActivity extends Hilt_ImmersiveActivity {
|
||||
private static final String TAG = "VdmImmersiveActivity";
|
||||
|
||||
// Approximately, see
|
||||
// https://developer.android.com/reference/android/util/DisplayMetrics#density
|
||||
private static final float DIP_TO_DPI = 160f;
|
||||
|
||||
@Inject ConnectionManager connectionManager;
|
||||
@Inject RemoteIo remoteIo;
|
||||
@Inject VirtualSensorController sensorController;
|
||||
@Inject AudioPlayer audioPlayer;
|
||||
@Inject InputManager inputManager;
|
||||
@Inject ConnectionManager mConnectionManager;
|
||||
@Inject RemoteIo mRemoteIo;
|
||||
@Inject VirtualSensorController mSensorController;
|
||||
@Inject AudioPlayer mAudioPlayer;
|
||||
@Inject InputManager mInputManager;
|
||||
|
||||
private DisplayController displayController;
|
||||
private final Consumer<RemoteEvent> remoteEventConsumer = this::processRemoteEvent;
|
||||
private DisplayController mDisplayController;
|
||||
private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
|
||||
|
||||
private final ConnectionManager.ConnectionCallback connectionCallback =
|
||||
private final ConnectionManager.ConnectionCallback mConnectionCallback =
|
||||
new ConnectionManager.ConnectionCallback() {
|
||||
@Override
|
||||
public void onConnected(String remoteDeviceName) {}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
@@ -91,20 +89,20 @@ public class ImmersiveActivity extends Hilt_ImmersiveActivity {
|
||||
new OnBackPressedCallback(true) {
|
||||
@Override
|
||||
public void handleOnBackPressed() {
|
||||
inputManager.sendBack(DEFAULT_DISPLAY);
|
||||
mInputManager.sendBack(DEFAULT_DISPLAY);
|
||||
}
|
||||
};
|
||||
getOnBackPressedDispatcher().addCallback(this, callback);
|
||||
|
||||
displayController = new DisplayController(DEFAULT_DISPLAY, remoteIo);
|
||||
displayController.setDpi((int) (getResources().getDisplayMetrics().density * DIP_TO_DPI));
|
||||
mDisplayController = new DisplayController(DEFAULT_DISPLAY, mRemoteIo);
|
||||
mDisplayController.setDpi((int) (getResources().getDisplayMetrics().density * DIP_TO_DPI));
|
||||
|
||||
TextureView textureView = findViewById(R.id.immersive_surface_view);
|
||||
textureView.setOnTouchListener(
|
||||
(v, event) -> {
|
||||
if (event.getDevice().supportsSource(InputDevice.SOURCE_TOUCHSCREEN)) {
|
||||
textureView.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
inputManager.sendInputEvent(
|
||||
mInputManager.sendInputEvent(
|
||||
InputDeviceType.DEVICE_TYPE_TOUCHSCREEN, event, DEFAULT_DISPLAY);
|
||||
}
|
||||
return true;
|
||||
@@ -112,53 +110,53 @@ public class ImmersiveActivity extends Hilt_ImmersiveActivity {
|
||||
textureView.setSurfaceTextureListener(
|
||||
new TextureView.SurfaceTextureListener() {
|
||||
@Override
|
||||
public void onSurfaceTextureUpdated(SurfaceTexture texture) {}
|
||||
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture texture) {}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureAvailable(
|
||||
SurfaceTexture texture, int width, int height) {
|
||||
displayController.setSurface(new Surface(texture), width, height);
|
||||
@NonNull SurfaceTexture texture, int width, int height) {
|
||||
mDisplayController.setSurface(new Surface(texture), width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
|
||||
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture texture) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceTextureSizeChanged(
|
||||
SurfaceTexture texture, int width, int height) {}
|
||||
@NonNull SurfaceTexture texture, int width, int height) {}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
connectionManager.addConnectionCallback(connectionCallback);
|
||||
remoteIo.addMessageConsumer(audioPlayer);
|
||||
remoteIo.addMessageConsumer(remoteEventConsumer);
|
||||
mConnectionManager.addConnectionCallback(mConnectionCallback);
|
||||
mRemoteIo.addMessageConsumer(mAudioPlayer);
|
||||
mRemoteIo.addMessageConsumer(mRemoteEventConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
connectionManager.removeConnectionCallback(connectionCallback);
|
||||
remoteIo.removeMessageConsumer(audioPlayer);
|
||||
remoteIo.removeMessageConsumer(remoteEventConsumer);
|
||||
mConnectionManager.removeConnectionCallback(mConnectionCallback);
|
||||
mRemoteIo.removeMessageConsumer(mAudioPlayer);
|
||||
mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
displayController.close();
|
||||
sensorController.close();
|
||||
mDisplayController.close();
|
||||
mSensorController.close();
|
||||
}
|
||||
|
||||
private void processRemoteEvent(RemoteEvent event) {
|
||||
if (event.hasStopStreaming() && !event.getStopStreaming().getPause()) {
|
||||
finish();
|
||||
} else if (event.hasStartStreaming()) {
|
||||
displayController.sendDisplayCapabilities();
|
||||
mDisplayController.sendDisplayCapabilities();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,14 +164,17 @@ public class ImmersiveActivity extends Hilt_ImmersiveActivity {
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
int keyCode = event.getKeyCode();
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
inputManager.sendHome(DEFAULT_DISPLAY);
|
||||
case KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
mInputManager.sendHome(DEFAULT_DISPLAY);
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
}
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
finish();
|
||||
return true;
|
||||
default:
|
||||
}
|
||||
default -> {
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,57 +47,57 @@ import javax.inject.Singleton;
|
||||
final class InputManager {
|
||||
private static final String TAG = "InputManager";
|
||||
|
||||
private final RemoteIo remoteIo;
|
||||
private final Settings settings;
|
||||
private final RemoteIo mRemoteIo;
|
||||
private final Settings mSettings;
|
||||
|
||||
private final Object lock = new Object();
|
||||
private final Object mLock = new Object();
|
||||
|
||||
@GuardedBy("lock")
|
||||
private int focusedDisplayId = Display.INVALID_DISPLAY;
|
||||
@GuardedBy("mLock")
|
||||
private int mFocusedDisplayId = Display.INVALID_DISPLAY;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private boolean isTrackingFocus = false;
|
||||
@GuardedBy("mLock")
|
||||
private boolean mIsTrackingFocus = false;
|
||||
|
||||
interface FocusListener {
|
||||
void onFocusChange(int focusedDisplayId);
|
||||
}
|
||||
|
||||
@GuardedBy("lock")
|
||||
private final List<FocusListener> focusListeners = new ArrayList<>();
|
||||
@GuardedBy("mLock")
|
||||
private final List<FocusListener> mFocusListeners = new ArrayList<>();
|
||||
|
||||
@GuardedBy("lock")
|
||||
private final Set<Integer> focusableDisplays = new HashSet<>();
|
||||
@GuardedBy("mLock")
|
||||
private final Set<Integer> mFocusableDisplays = new HashSet<>();
|
||||
|
||||
@Inject
|
||||
InputManager(RemoteIo remoteIo, Settings settings) {
|
||||
this.remoteIo = remoteIo;
|
||||
this.settings = settings;
|
||||
mRemoteIo = remoteIo;
|
||||
mSettings = settings;
|
||||
}
|
||||
|
||||
void addFocusListener(FocusListener focusListener) {
|
||||
synchronized (lock) {
|
||||
focusListeners.add(focusListener);
|
||||
synchronized (mLock) {
|
||||
mFocusListeners.add(focusListener);
|
||||
}
|
||||
}
|
||||
|
||||
void removeFocusListener(FocusListener focusListener) {
|
||||
synchronized (lock) {
|
||||
focusListeners.remove(focusListener);
|
||||
synchronized (mLock) {
|
||||
mFocusListeners.remove(focusListener);
|
||||
}
|
||||
}
|
||||
|
||||
void addFocusableDisplay(int displayId) {
|
||||
synchronized (lock) {
|
||||
if (focusableDisplays.add(displayId)) {
|
||||
synchronized (mLock) {
|
||||
if (mFocusableDisplays.add(displayId)) {
|
||||
setFocusedDisplayId(displayId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeFocusableDisplay(int displayId) {
|
||||
synchronized (lock) {
|
||||
focusableDisplays.remove(Integer.valueOf(displayId));
|
||||
if (displayId == focusedDisplayId) {
|
||||
synchronized (mLock) {
|
||||
mFocusableDisplays.remove(displayId);
|
||||
if (displayId == mFocusedDisplayId) {
|
||||
setFocusedDisplayId(updateFocusedDisplayId());
|
||||
}
|
||||
}
|
||||
@@ -105,21 +105,21 @@ final class InputManager {
|
||||
|
||||
void updateFocusTracking() {
|
||||
boolean shouldTrackFocus =
|
||||
settings.dpadEnabled
|
||||
|| settings.navTouchpadEnabled
|
||||
|| settings.externalKeyboardEnabled
|
||||
|| settings.externalMouseEnabled;
|
||||
mSettings.dpadEnabled
|
||||
|| mSettings.navTouchpadEnabled
|
||||
|| mSettings.externalKeyboardEnabled
|
||||
|| mSettings.externalMouseEnabled;
|
||||
|
||||
List<FocusListener> listenersToNotify = Collections.emptyList();
|
||||
final List<FocusListener> listenersToNotify;
|
||||
int focusedDisplayIdToNotify = Display.INVALID_DISPLAY;
|
||||
synchronized (lock) {
|
||||
if (shouldTrackFocus != isTrackingFocus) {
|
||||
isTrackingFocus = shouldTrackFocus;
|
||||
synchronized (mLock) {
|
||||
if (shouldTrackFocus != mIsTrackingFocus) {
|
||||
mIsTrackingFocus = shouldTrackFocus;
|
||||
}
|
||||
if (isTrackingFocus) {
|
||||
focusedDisplayIdToNotify = focusedDisplayId;
|
||||
if (mIsTrackingFocus) {
|
||||
focusedDisplayIdToNotify = mFocusedDisplayId;
|
||||
}
|
||||
listenersToNotify = new ArrayList<>(focusListeners);
|
||||
listenersToNotify = new ArrayList<>(mFocusListeners);
|
||||
}
|
||||
for (FocusListener focusListener : listenersToNotify) {
|
||||
focusListener.onFocusChange(focusedDisplayIdToNotify);
|
||||
@@ -152,30 +152,30 @@ final class InputManager {
|
||||
*/
|
||||
public void sendInputEventToFocusedDisplay(InputDeviceType deviceType, InputEvent inputEvent) {
|
||||
int targetDisplay;
|
||||
synchronized (lock) {
|
||||
if (!isTrackingFocus || focusedDisplayId == Display.INVALID_DISPLAY) {
|
||||
synchronized (mLock) {
|
||||
if (!mIsTrackingFocus || mFocusedDisplayId == Display.INVALID_DISPLAY) {
|
||||
return;
|
||||
}
|
||||
targetDisplay = focusedDisplayId;
|
||||
targetDisplay = mFocusedDisplayId;
|
||||
}
|
||||
switch (deviceType) {
|
||||
case DEVICE_TYPE_NAVIGATION_TOUCHPAD:
|
||||
if (!settings.navTouchpadEnabled) {
|
||||
if (!mSettings.navTouchpadEnabled) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case DEVICE_TYPE_DPAD:
|
||||
if (!settings.dpadEnabled) {
|
||||
if (!mSettings.dpadEnabled) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case DEVICE_TYPE_MOUSE:
|
||||
if (!settings.externalMouseEnabled) {
|
||||
if (!mSettings.externalMouseEnabled) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case DEVICE_TYPE_KEYBOARD:
|
||||
if (!settings.externalKeyboardEnabled) {
|
||||
if (!mSettings.externalKeyboardEnabled) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
@@ -206,7 +206,7 @@ final class InputManager {
|
||||
|
||||
void sendHome(int displayId) {
|
||||
setFocusedDisplayId(displayId);
|
||||
remoteIo.sendMessage(
|
||||
mRemoteIo.sendMessage(
|
||||
RemoteEvent.newBuilder()
|
||||
.setDisplayId(displayId)
|
||||
.setHomeEvent(RemoteHomeEvent.newBuilder())
|
||||
@@ -296,7 +296,7 @@ final class InputManager {
|
||||
}
|
||||
|
||||
private void sendInputEvent(RemoteInputEvent inputEvent, int displayId) {
|
||||
remoteIo.sendMessage(
|
||||
mRemoteIo.sendMessage(
|
||||
RemoteEvent.newBuilder().setDisplayId(displayId).setInputEvent(inputEvent).build());
|
||||
}
|
||||
|
||||
@@ -305,21 +305,21 @@ final class InputManager {
|
||||
}
|
||||
|
||||
private int updateFocusedDisplayId() {
|
||||
synchronized (lock) {
|
||||
if (focusableDisplays.contains(focusedDisplayId)) {
|
||||
return focusedDisplayId;
|
||||
synchronized (mLock) {
|
||||
if (mFocusableDisplays.contains(mFocusedDisplayId)) {
|
||||
return mFocusedDisplayId;
|
||||
}
|
||||
return Iterables.getFirst(focusableDisplays, Display.INVALID_DISPLAY);
|
||||
return Iterables.getFirst(mFocusableDisplays, Display.INVALID_DISPLAY);
|
||||
}
|
||||
}
|
||||
|
||||
private void setFocusedDisplayId(int displayId) {
|
||||
List<FocusListener> listenersToNotify = Collections.emptyList();
|
||||
synchronized (lock) {
|
||||
if (displayId != focusedDisplayId) {
|
||||
focusedDisplayId = displayId;
|
||||
if (isTrackingFocus) {
|
||||
listenersToNotify = new ArrayList<>(focusListeners);
|
||||
synchronized (mLock) {
|
||||
if (displayId != mFocusedDisplayId) {
|
||||
mFocusedDisplayId = displayId;
|
||||
if (mIsTrackingFocus) {
|
||||
listenersToNotify = new ArrayList<>(mFocusListeners);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,45 +49,45 @@ import javax.inject.Inject;
|
||||
@AndroidEntryPoint(AppCompatActivity.class)
|
||||
public class MainActivity extends Hilt_MainActivity {
|
||||
|
||||
@Inject RemoteIo remoteIo;
|
||||
@Inject ConnectionManager connectionManager;
|
||||
@Inject InputManager inputManager;
|
||||
@Inject VirtualSensorController sensorController;
|
||||
@Inject AudioPlayer audioPlayer;
|
||||
@Inject Settings settings;
|
||||
@Inject RemoteIo mRemoteIo;
|
||||
@Inject ConnectionManager mConnectionManager;
|
||||
@Inject InputManager mInputManager;
|
||||
@Inject VirtualSensorController mSensorController;
|
||||
@Inject AudioPlayer mAudioPlayer;
|
||||
@Inject Settings mSettings;
|
||||
|
||||
private final Consumer<RemoteEvent> remoteEventConsumer = this::processRemoteEvent;
|
||||
private DisplayAdapter displayAdapter;
|
||||
private final InputManager.FocusListener focusListener = this::onDisplayFocusChange;
|
||||
private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
|
||||
private DisplayAdapter mDisplayAdapter;
|
||||
private final InputManager.FocusListener mFocusListener = this::onDisplayFocusChange;
|
||||
|
||||
private final ConnectionManager.ConnectionCallback connectionCallback =
|
||||
private final ConnectionManager.ConnectionCallback mConnectionCallback =
|
||||
new ConnectionManager.ConnectionCallback() {
|
||||
|
||||
@Override
|
||||
public void onConnecting(String remoteDeviceName) {
|
||||
connectionManager.stopAdvertising();
|
||||
mConnectionManager.stopAdvertising();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(String remoteDeviceName) {
|
||||
remoteIo.sendMessage(
|
||||
mRemoteIo.sendMessage(
|
||||
RemoteEvent.newBuilder()
|
||||
.setDeviceCapabilities(
|
||||
DeviceCapabilities.newBuilder()
|
||||
.setDeviceName(Build.MODEL)
|
||||
.addAllSensorCapabilities(
|
||||
(sensorController
|
||||
(mSensorController
|
||||
.getSensorCapabilities())))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
if (displayAdapter != null) {
|
||||
runOnUiThread(displayAdapter::clearDisplays);
|
||||
if (mDisplayAdapter != null) {
|
||||
runOnUiThread(mDisplayAdapter::clearDisplays);
|
||||
}
|
||||
|
||||
connectionManager.startAdvertising();
|
||||
mConnectionManager.startAdvertising();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -104,36 +104,36 @@ public class MainActivity extends Hilt_MainActivity {
|
||||
displaysView.setLayoutManager(
|
||||
new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
|
||||
displaysView.setItemAnimator(null);
|
||||
displayAdapter = new DisplayAdapter(displaysView, remoteIo, inputManager);
|
||||
displaysView.setAdapter(displayAdapter);
|
||||
mDisplayAdapter = new DisplayAdapter(displaysView, mRemoteIo, mInputManager);
|
||||
displaysView.setAdapter(mDisplayAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
connectionManager.addConnectionCallback(connectionCallback);
|
||||
connectionManager.startAdvertising();
|
||||
inputManager.addFocusListener(focusListener);
|
||||
remoteIo.addMessageConsumer(audioPlayer);
|
||||
remoteIo.addMessageConsumer(remoteEventConsumer);
|
||||
mConnectionManager.addConnectionCallback(mConnectionCallback);
|
||||
mConnectionManager.startAdvertising();
|
||||
mInputManager.addFocusListener(mFocusListener);
|
||||
mRemoteIo.addMessageConsumer(mAudioPlayer);
|
||||
mRemoteIo.addMessageConsumer(mRemoteEventConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
inputManager.removeFocusListener(focusListener);
|
||||
connectionManager.removeConnectionCallback(connectionCallback);
|
||||
connectionManager.stopAdvertising();
|
||||
remoteIo.removeMessageConsumer(remoteEventConsumer);
|
||||
remoteIo.removeMessageConsumer(audioPlayer);
|
||||
mInputManager.removeFocusListener(mFocusListener);
|
||||
mConnectionManager.removeConnectionCallback(mConnectionCallback);
|
||||
mConnectionManager.stopAdvertising();
|
||||
mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
|
||||
mRemoteIo.removeMessageConsumer(mAudioPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
displayAdapter.clearDisplays();
|
||||
connectionManager.disconnect();
|
||||
sensorController.close();
|
||||
mDisplayAdapter.clearDisplays();
|
||||
mConnectionManager.disconnect();
|
||||
mSensorController.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -142,7 +142,7 @@ public class MainActivity extends Hilt_MainActivity {
|
||||
|| !event.getDevice().supportsSource(InputDevice.SOURCE_KEYBOARD)) {
|
||||
return false;
|
||||
}
|
||||
inputManager.sendInputEventToFocusedDisplay(InputDeviceType.DEVICE_TYPE_KEYBOARD, event);
|
||||
mInputManager.sendInputEventToFocusedDisplay(InputDeviceType.DEVICE_TYPE_KEYBOARD, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -153,18 +153,11 @@ public class MainActivity extends Hilt_MainActivity {
|
||||
for (int i = 0; i < menu.size(); ++i) {
|
||||
MenuItem item = menu.getItem(i);
|
||||
switch (item.getItemId()) {
|
||||
case R.id.enable_dpad:
|
||||
item.setChecked(settings.dpadEnabled);
|
||||
break;
|
||||
case R.id.enable_nav_touchpad:
|
||||
item.setChecked(settings.navTouchpadEnabled);
|
||||
break;
|
||||
case R.id.enable_external_keyboard:
|
||||
item.setChecked(settings.externalKeyboardEnabled);
|
||||
break;
|
||||
case R.id.enable_external_mouse:
|
||||
item.setChecked(settings.externalMouseEnabled);
|
||||
break;
|
||||
case R.id.enable_dpad -> item.setChecked(mSettings.dpadEnabled);
|
||||
case R.id.enable_nav_touchpad -> item.setChecked(mSettings.navTouchpadEnabled);
|
||||
case R.id.enable_external_keyboard -> item.setChecked(
|
||||
mSettings.externalKeyboardEnabled);
|
||||
case R.id.enable_external_mouse -> item.setChecked(mSettings.externalMouseEnabled);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -175,23 +168,17 @@ public class MainActivity extends Hilt_MainActivity {
|
||||
item.setChecked(!item.isChecked());
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case R.id.enable_dpad:
|
||||
settings.dpadEnabled = item.isChecked();
|
||||
break;
|
||||
case R.id.enable_nav_touchpad:
|
||||
settings.navTouchpadEnabled = item.isChecked();
|
||||
break;
|
||||
case R.id.enable_external_keyboard:
|
||||
settings.externalKeyboardEnabled = item.isChecked();
|
||||
break;
|
||||
case R.id.enable_external_mouse:
|
||||
settings.externalMouseEnabled = item.isChecked();
|
||||
break;
|
||||
default:
|
||||
case R.id.enable_dpad -> mSettings.dpadEnabled = item.isChecked();
|
||||
case R.id.enable_nav_touchpad -> mSettings.navTouchpadEnabled = item.isChecked();
|
||||
case R.id.enable_external_keyboard ->
|
||||
mSettings.externalKeyboardEnabled = item.isChecked();
|
||||
case R.id.enable_external_mouse -> mSettings.externalMouseEnabled = item.isChecked();
|
||||
default -> {
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
inputManager.updateFocusTracking();
|
||||
mInputManager.updateFocusTracking();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -202,27 +189,27 @@ public class MainActivity extends Hilt_MainActivity {
|
||||
} else {
|
||||
runOnUiThread(
|
||||
() ->
|
||||
displayAdapter.addDisplay(
|
||||
mDisplayAdapter.addDisplay(
|
||||
event.getStartStreaming().getHomeEnabled()));
|
||||
}
|
||||
} else if (event.hasStopStreaming()) {
|
||||
runOnUiThread(() -> displayAdapter.removeDisplay(event.getDisplayId()));
|
||||
runOnUiThread(() -> mDisplayAdapter.removeDisplay(event.getDisplayId()));
|
||||
} else if (event.hasDisplayRotation()) {
|
||||
runOnUiThread(() -> displayAdapter.rotateDisplay(event));
|
||||
runOnUiThread(() -> mDisplayAdapter.rotateDisplay(event));
|
||||
} else if (event.hasDisplayChangeEvent()) {
|
||||
runOnUiThread(() -> displayAdapter.processDisplayChange(event));
|
||||
runOnUiThread(() -> mDisplayAdapter.processDisplayChange(event));
|
||||
}
|
||||
}
|
||||
|
||||
private void onDisplayFocusChange(int displayId) {
|
||||
findViewById(R.id.dpad_fragment_container)
|
||||
.setVisibility(
|
||||
settings.dpadEnabled && displayId != Display.INVALID_DISPLAY
|
||||
mSettings.dpadEnabled && displayId != Display.INVALID_DISPLAY
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
findViewById(R.id.nav_touchpad_fragment_container)
|
||||
.setVisibility(
|
||||
settings.navTouchpadEnabled && displayId != Display.INVALID_DISPLAY
|
||||
mSettings.navTouchpadEnabled && displayId != Display.INVALID_DISPLAY
|
||||
? View.VISIBLE
|
||||
: View.GONE);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ import javax.inject.Inject;
|
||||
@AndroidEntryPoint(Fragment.class)
|
||||
public final class NavTouchpadFragment extends Hilt_NavTouchpadFragment {
|
||||
|
||||
@Inject InputManager inputManager;
|
||||
@Inject InputManager mInputManager;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
@@ -46,7 +46,7 @@ public final class NavTouchpadFragment extends Hilt_NavTouchpadFragment {
|
||||
TextView navTouchpad = view.findViewById(R.id.nav_touchpad);
|
||||
navTouchpad.setOnTouchListener(
|
||||
(v, event) -> {
|
||||
inputManager.sendInputEventToFocusedDisplay(
|
||||
mInputManager.sendInputEventToFocusedDisplay(
|
||||
InputDeviceType.DEVICE_TYPE_NAVIGATION_TOUCHPAD, event);
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -22,10 +22,10 @@ import javax.inject.Singleton;
|
||||
/** Settings known to the VDM Demo Client application */
|
||||
@Singleton
|
||||
final class Settings {
|
||||
boolean dpadEnabled = false;
|
||||
boolean navTouchpadEnabled = false;
|
||||
boolean externalKeyboardEnabled = false;
|
||||
boolean externalMouseEnabled = false;
|
||||
public boolean dpadEnabled = false;
|
||||
public boolean navTouchpadEnabled = false;
|
||||
public boolean externalKeyboardEnabled = false;
|
||||
public boolean externalMouseEnabled = false;
|
||||
|
||||
@Inject
|
||||
Settings() {}
|
||||
|
||||
@@ -43,17 +43,17 @@ import javax.inject.Inject;
|
||||
@ActivityScoped
|
||||
final class VirtualSensorController implements AutoCloseable {
|
||||
|
||||
private final RemoteIo remoteIo;
|
||||
private final Consumer<RemoteEvent> remoteEventConsumer = this::processRemoteEvent;
|
||||
private final SensorManager sensorManager;
|
||||
private final HandlerThread listenerThread;
|
||||
private final Handler handler;
|
||||
private final RemoteIo mRemoteIo;
|
||||
private final Consumer<RemoteEvent> mRemoteEventConsumer = this::processRemoteEvent;
|
||||
private final SensorManager mSensorManager;
|
||||
private final HandlerThread mListenerThread;
|
||||
private final Handler mHandler;
|
||||
|
||||
private final SensorEventListener sensorEventListener =
|
||||
new SensorEventListener() {
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
remoteIo.sendMessage(
|
||||
mRemoteIo.sendMessage(
|
||||
RemoteEvent.newBuilder()
|
||||
.setSensorEvent(
|
||||
RemoteSensorEvent.newBuilder()
|
||||
@@ -68,25 +68,25 @@ final class VirtualSensorController implements AutoCloseable {
|
||||
|
||||
@Inject
|
||||
VirtualSensorController(@ApplicationContext Context context, RemoteIo remoteIo) {
|
||||
this.sensorManager = context.getSystemService(SensorManager.class);
|
||||
this.remoteIo = remoteIo;
|
||||
mSensorManager = context.getSystemService(SensorManager.class);
|
||||
mRemoteIo = remoteIo;
|
||||
|
||||
listenerThread = new HandlerThread("VirtualSensorListener");
|
||||
listenerThread.start();
|
||||
handler = new Handler(listenerThread.getLooper());
|
||||
mListenerThread = new HandlerThread("VirtualSensorListener");
|
||||
mListenerThread.start();
|
||||
mHandler = new Handler(mListenerThread.getLooper());
|
||||
|
||||
remoteIo.addMessageConsumer(remoteEventConsumer);
|
||||
remoteIo.addMessageConsumer(mRemoteEventConsumer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
sensorManager.unregisterListener(sensorEventListener);
|
||||
listenerThread.quitSafely();
|
||||
remoteIo.removeMessageConsumer(remoteEventConsumer);
|
||||
mSensorManager.unregisterListener(sensorEventListener);
|
||||
mListenerThread.quitSafely();
|
||||
mRemoteIo.removeMessageConsumer(mRemoteEventConsumer);
|
||||
}
|
||||
|
||||
public List<SensorCapabilities> getSensorCapabilities() {
|
||||
return sensorManager.getSensorList(Sensor.TYPE_ALL).stream()
|
||||
return mSensorManager.getSensorList(Sensor.TYPE_ALL).stream()
|
||||
.map(
|
||||
sensor ->
|
||||
SensorCapabilities.newBuilder()
|
||||
@@ -107,19 +107,19 @@ final class VirtualSensorController implements AutoCloseable {
|
||||
return;
|
||||
}
|
||||
SensorConfiguration config = remoteEvent.getSensorConfiguration();
|
||||
Sensor sensor = sensorManager.getDefaultSensor(config.getSensorType());
|
||||
Sensor sensor = mSensorManager.getDefaultSensor(config.getSensorType());
|
||||
if (sensor == null) {
|
||||
return;
|
||||
}
|
||||
if (config.getEnabled()) {
|
||||
sensorManager.registerListener(
|
||||
mSensorManager.registerListener(
|
||||
sensorEventListener,
|
||||
sensor,
|
||||
config.getSamplingPeriodUs(),
|
||||
config.getBatchReportingLatencyUs(),
|
||||
handler);
|
||||
mHandler);
|
||||
} else {
|
||||
sensorManager.unregisterListener(sensorEventListener, sensor);
|
||||
mSensorManager.unregisterListener(sensorEventListener, sensor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user