Skip to content

Commit

Permalink
[Vision Glass] UI to realign controller on startup
Browse files Browse the repository at this point in the history
Display a dialog informing the user that it is necessary to
point the phone straight ahead to set up the controller.
This dialog will be dismissed automatically after 5 seconds,
clicking the realign button on it will close it faster.
A similar dialog is displayed on the VR environment.
  • Loading branch information
felipeerias committed May 15, 2024
1 parent b5a787c commit 4a9379f
Show file tree
Hide file tree
Showing 9 changed files with 282 additions and 8 deletions.
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2557,5 +2557,7 @@ the Select` button. When clicked it closes all the previously selected tabs -->
<string name="vision_glass_disconnected_message">Please connect Vision Glass</string>
<!-- Vision Glass: instruct the user to unplug the device and try again -->
<string name="vision_glass_error_message">An error happened.\nPlease try again.</string>
<!-- Vision Glass: instruct the user to point the phone straight ahead to re-align the controller. -->
<string name="vision_glass_realign_dialog_explanation">Please point your phone straight ahead to center the controller.</string>

</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private void init() {
// metrics
mStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics());
mCornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, getResources().getDisplayMetrics());
mSquarePadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, getResources().getDisplayMetrics());
mSquarePadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics());
mCirclePadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getResources().getDisplayMetrics());

mPaint = new Paint();
Expand All @@ -60,17 +60,22 @@ protected void onDraw(Canvas canvas) {

// Draw square
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAlpha(150);
mPaint.setAlpha(120);
mSquareRect.set(mSquarePadding, mSquarePadding, getWidth() - mSquarePadding, getHeight() - mSquarePadding);

canvas.drawRoundRect(mSquareRect, mCornerRadius, mCornerRadius, mPaint);

// Draw crosshair
float crosshairLength = getWidth() / 12f;
canvas.drawLine(getWidth() / 2f - crosshairLength, getHeight() / 2f, getWidth() / 2f + crosshairLength, getHeight() / 2f, mPaint);
canvas.drawLine(getWidth() / 2f, getHeight() / 2f - crosshairLength, getWidth() / 2f, getHeight() / 2f + crosshairLength, mPaint);

// Draw circle
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha(255);
float radius = Math.min(getWidth(), getHeight()) / 10f;
float centerX = mCirclePadding + ((mPointPosition.x + 1) * (getWidth() - mCirclePadding) / 2f);
float centerY = mCirclePadding + ((mPointPosition.y + 1) * (getHeight() - mCirclePadding) / 2f);
float centerX = mCirclePadding + ((mPointPosition.x + 1) / 2f) * (getWidth() - 2 * mCirclePadding);
float centerY = mCirclePadding + ((mPointPosition.y + 1) / 2f) * (getHeight() - 2 * mCirclePadding);

canvas.drawCircle(centerX, centerY, radius, mPaint);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package com.igalia.wolvic;

import android.content.Context;
import android.content.res.Configuration;
import android.util.AttributeSet;
import android.widget.Button;

import com.igalia.wolvic.ui.widgets.WidgetPlacement;
import com.igalia.wolvic.ui.widgets.dialogs.UIDialog;

public class AlignNotificationUIDialog extends UIDialog {

public AlignNotificationUIDialog(Context aContext) {
super(aContext);
updateUI();
}

public AlignNotificationUIDialog(Context aContext, AttributeSet aAttrs) {
super(aContext, aAttrs);
updateUI();
}

public AlignNotificationUIDialog(Context aContext, AttributeSet aAttrs, int aDefStyle) {
super(aContext, aAttrs, aDefStyle);
updateUI();
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateUI();
}

private void updateUI() {
removeAllViews();
inflate(getContext(), R.layout.dialog_align, this);

Button okButton = findViewById(R.id.okButton);
okButton.setOnClickListener(view -> {
post(this::onDismiss);
});
}

@Override
protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.visible = false;
aPlacement.width = WidgetPlacement.dpDimension(getContext(), R.dimen.prompt_dialog_width);
aPlacement.height = WidgetPlacement.dpDimension(getContext(), R.dimen.prompt_dialog_height);
aPlacement.anchorX = 0.5f;
aPlacement.anchorY = 0.5f;
aPlacement.parentAnchorY = 0.0f;
aPlacement.parentAnchorX = 0.5f;
aPlacement.translationY = WidgetPlacement.unitFromMeters(getContext(), R.dimen.settings_world_y) -
WidgetPlacement.unitFromMeters(getContext(), R.dimen.window_world_y);
updatePlacementTranslationZ();
}

@Override
public void updatePlacementTranslationZ() {
getPlacement().translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.settings_world_z) -
WidgetPlacement.getWindowWorldZMeters(getContext());
}

@Override
public void show(@ShowFlags int aShowFlags) {
mWidgetPlacement.parentHandle = mWidgetManager.getFocusedWindow().getHandle();

super.show(aShowFlags);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.igalia.wolvic;

import android.os.Bundle;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;

public class AlignPhoneDialogFragment extends DialogFragment {
private final int mThemeResId;
private AlignDynamicButton mRealignButton;
private View.OnClickListener mRealignButtonClickListener;

public AlignPhoneDialogFragment(int themeResId) {
mThemeResId = themeResId;
}

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
ContextThemeWrapper themedContext = new ContextThemeWrapper(getContext(), mThemeResId);
LayoutInflater themedInflater = getLayoutInflater().cloneInContext(themedContext);
View view = themedInflater.inflate(R.layout.dialog_align_phone, container);
mRealignButton = view.findViewById(R.id.realign_button);
if (mRealignButtonClickListener != null)
mRealignButton.setOnClickListener(mRealignButtonClickListener);

return view;
}

public void updatePosition(float x, float y) {
mRealignButton.updatePosition(x, y);
}

public void setOnRealignButtonClickListener(View.OnClickListener listener) {
mRealignButtonClickListener = listener;
if (mRealignButton != null)
mRealignButton.setOnClickListener(listener);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public LiveData<ConnectionState> getConnectionState() {
}

public void updateConnectionState(ConnectionState newState) {
if (newState.equals(mConnectionState.getValue()))
return;

mConnectionState.postValue(newState);

if (newState != ConnectionState.ACTIVE) {
Expand Down
60 changes: 56 additions & 4 deletions app/src/visionglass/java/com/igalia/wolvic/PlatformActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import android.hardware.display.DisplayManager;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Display;
Expand All @@ -32,11 +34,11 @@
import android.widget.Button;
import android.widget.SeekBar;

import androidx.activity.ComponentActivity;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;

import com.huawei.usblib.DisplayMode;
Expand All @@ -48,6 +50,7 @@
import com.igalia.wolvic.browser.api.WMediaSession;
import com.igalia.wolvic.browser.api.WSession;
import com.igalia.wolvic.databinding.VisionglassLayoutBinding;
import com.igalia.wolvic.ui.widgets.UIWidget;
import com.igalia.wolvic.ui.widgets.WidgetManagerDelegate;
import com.igalia.wolvic.utils.SystemUtils;

Expand All @@ -57,12 +60,14 @@
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class PlatformActivity extends ComponentActivity implements SensorEventListener, OnConnectionListener {
public class PlatformActivity extends FragmentActivity implements SensorEventListener, OnConnectionListener {
static String LOGTAG = SystemUtils.createLogtag(PlatformActivity.class);

public static final String HUAWEI_USB_PERMISSION = "com.huawei.usblib.USB_PERMISSION";
private static final int REORIENT_UI_DELAY_MS = 5_000;

private boolean mIsAskingForPermission;
private boolean mInitialControllerReorientDone = false;
private PhoneUIViewModel mViewModel;
VisionglassLayoutBinding mBinding;
private DisplayManager mDisplayManager;
Expand All @@ -71,6 +76,9 @@ public class PlatformActivity extends ComponentActivity implements SensorEventLi
private int mDisplayModeRetryCount = 0;
private int mUSBPermissionRequestCount = 0;
private boolean mSwitchedTo3DMode = false;
private AlignPhoneDialogFragment mAlignDialogFragment;
private AlignNotificationUIDialog mAlignNotificationUIDialog;
private Handler mUiHandler;

@SuppressWarnings("unused")
public static boolean filterPermission(final String aPermission) {
Expand Down Expand Up @@ -187,6 +195,40 @@ private void registerPhoneIMUListener() {
mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR), SensorManager.SENSOR_DELAY_NORMAL);
}

private void reorientController() {
mInitialControllerReorientDone = true;
mAlignDialogFragment.dismiss();

if (mAlignNotificationUIDialog != null) {
mAlignNotificationUIDialog.hide(UIWidget.REMOVE_WIDGET);
mAlignNotificationUIDialog = null;
}

mSensorManager.unregisterListener(this);
registerPhoneIMUListener();
queueRunnable(this::calibrateController);
}

private void onConnectionStateChanged(PhoneUIViewModel.ConnectionState connectionState) {
Log.d(LOGTAG, "Connection state updated: " + connectionState);

if (connectionState == PhoneUIViewModel.ConnectionState.ACTIVE) {
mAlignDialogFragment.show(getSupportFragmentManager(), "AlignDialogFragment");

if (mAlignNotificationUIDialog == null) {
mAlignNotificationUIDialog = new AlignNotificationUIDialog(this);
}
mAlignNotificationUIDialog.show(UIWidget.REQUEST_FOCUS);

mUiHandler.postDelayed(() -> {
if (!mInitialControllerReorientDone)
reorientController();
}, REORIENT_UI_DELAY_MS);
} else if (mAlignDialogFragment.isAdded()) {
mAlignDialogFragment.dismiss();
}
}

private void initVisionGlassPhoneUI() {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Expand All @@ -198,12 +240,16 @@ private void initVisionGlassPhoneUI() {
mBinding = DataBindingUtil.inflate(themedInflater, R.layout.visionglass_layout, null, false);
setContentView(mBinding.getRoot());

mAlignDialogFragment = new AlignPhoneDialogFragment(R.style.Theme_WolvicPhone);
mAlignDialogFragment.setOnRealignButtonClickListener(v -> {
reorientController();
});

mViewModel = new ViewModelProvider(this).get(PhoneUIViewModel.class);
mBinding.setViewModel(mViewModel);
mBinding.setLifecycleOwner(this);

mViewModel.getConnectionState().observe(this, connectionState ->
Log.d(LOGTAG, "Connection state updated: " + connectionState));
mViewModel.getConnectionState().observe(this, this::onConnectionStateChanged);

mBinding.voiceSearchButton.setEnabled(false);

Expand All @@ -216,6 +262,8 @@ private void initVisionGlassPhoneUI() {
Button backButton = findViewById(R.id.back_button);
backButton.setOnClickListener(v -> onBackPressed());

mUiHandler = new Handler(Looper.getMainLooper());

getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

Expand Down Expand Up @@ -302,6 +350,10 @@ public void onSensorChanged(SensorEvent event) {
queueRunnable(() -> setControllerOrientation(quaternion[1], quaternion[3], quaternion[2], quaternion[0]));

mBinding.realignButton.updatePosition(-quaternion[3], -quaternion[1]);

if (mAlignDialogFragment != null && mAlignDialogFragment.isVisible()) {
mAlignDialogFragment.updatePosition(-quaternion[3], -quaternion[1]);
}
}

@Override
Expand Down
20 changes: 20 additions & 0 deletions app/src/visionglass/res/drawable/reorient_phone.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="500dp"
android:height="300dp"
android:viewportWidth="132.29"
android:viewportHeight="79.38">
<path
android:pathData="m32.06,31.22 l34.16,-13.23 34.11,13.23 -17.8,-0.23 5.24,21.4L44.61,52.39l5.21,-21.44 -17.76,0.27"
android:strokeLineJoin="round"
android:strokeWidth="3.175"
android:fillColor="#00000000"
android:strokeColor="#f9f9f9"
android:strokeLineCap="round"/>
<path
android:pathData="m2.16,60.59 l0.84,11.91h126.37l0.75,-11.91M35.25,6.88 L2.16,60.59L130.13,60.59L97.11,6.88L35.25,6.88"
android:strokeLineJoin="round"
android:strokeWidth="3.175"
android:fillColor="#00000000"
android:strokeColor="#f9f9f9"
android:strokeLineCap="round"/>
</vector>
47 changes: 47 additions & 0 deletions app/src/visionglass/res/layout/dialog_align.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/prompt_dialog_width"
android:orientation="vertical"
android:layout_height="@dimen/prompt_dialog_height"
android:background="@drawable/dialog_background"
android:paddingStart="30dp"
android:paddingTop="20dp"
android:paddingEnd="30dp"
android:paddingBottom="30dp">

<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@id/reorientImage"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:singleLine="false"
android:text="@string/vision_glass_realign_dialog_explanation"
android:textColor="@color/fog"
android:textSize="@dimen/text_big_size"
android:textStyle="bold" />

<ImageView
android:id="@+id/reorientImage"
android:layout_width="250dp"
android:layout_height="0dp"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:src="@drawable/reorient_phone" />

<Button
android:id="@+id/okButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="@drawable/dialog_highlighted_button_background"
android:fontFamily="sans-serif"
android:minWidth="120dp"
android:padding="10dp"
android:scaleType="fitCenter"
android:text="@string/ok_button"
android:textColor="@drawable/prompt_button_text_color"
android:textStyle="bold" />

</LinearLayout>

0 comments on commit 4a9379f

Please sign in to comment.