diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java
index b1e416780..0bdff7af4 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java
@@ -1274,6 +1274,11 @@ public void openNewWindow(String uri) {
newWindow.getSessionStack().newSessionWithUrl(uri);
}
+ @Override
+ public WindowWidget getFocusedWindow() {
+ return mWindows.getFocusedWindow();
+ }
+
private native void addWidgetNative(int aHandle, WidgetPlacement aPlacement);
private native void updateWidgetNative(int aHandle, WidgetPlacement aPlacement);
private native void updateVisibleWidgetsNative();
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java
index d923a828a..067ec7180 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java
@@ -52,6 +52,7 @@ SettingsStore getInstance(final @NonNull Context aContext) {
public final static boolean TRACKING_DEFAULT = true;
public final static boolean NOTIFICATIONS_DEFAULT = true;
public final static boolean SPEECH_DATA_COLLECTION_DEFAULT = false;
+ public final static boolean SPEECH_DATA_COLLECTION_REVIEWED_DEFAULT = false;
public final static boolean SERVO_DEFAULT = false;
public final static int UA_MODE_DEFAULT = GeckoSessionSettings.USER_AGENT_MODE_VR;
public final static int INPUT_MODE_DEFAULT = 1;
@@ -542,5 +543,16 @@ public void setNotificationsEnabled(boolean isEnabled) {
editor.putBoolean(mContext.getString(R.string.settings_key_notifications), isEnabled);
editor.commit();
}
+
+ public boolean isSpeechDataCollectionReviewed() {
+ return mPrefs.getBoolean(
+ mContext.getString(R.string.settings_key_speech_data_collection_reviewed), SPEECH_DATA_COLLECTION_REVIEWED_DEFAULT);
+ }
+
+ public void setSpeechDataCollectionReviewed(boolean isEnabled) {
+ SharedPreferences.Editor editor = mPrefs.edit();
+ editor.putBoolean(mContext.getString(R.string.settings_key_speech_data_collection_reviewed), isEnabled);
+ editor.commit();
+ }
}
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java
index 889cac8e9..79ebd778f 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarWidget.java
@@ -574,7 +574,7 @@ private void enterVRVideo(@VideoProjectionMenuWidget.VideoProjectionFlags int aP
this.setVisible(false);
if (mFullScreenMedia != null && mFullScreenMedia.getWidth() > 0 && mFullScreenMedia.getHeight() > 0) {
final boolean resetBorder = aProjection == VideoProjectionMenuWidget.VIDEO_PROJECTION_360 ||
- aProjection == VideoProjectionMenuWidget.VIDEO_PROJECTION_360_STEREO;
+ aProjection == VideoProjectionMenuWidget.VIDEO_PROJECTION_360_STEREO;
mAttachedWindow.enableVRVideoMode(mFullScreenMedia.getWidth(), mFullScreenMedia.getHeight(), resetBorder);
// Handle video resize while in VR video playback
mFullScreenMedia.setResizeDelegate((width, height) -> {
@@ -844,6 +844,7 @@ public void OnVoiceSearchClicked() {
mVoiceSearchWidget.hide(REMOVE_WIDGET);
} else {
+ mVoiceSearchWidget.getPlacement().parentHandle = mAttachedWindow.getHandle();
mVoiceSearchWidget.show(REQUEST_FOCUS);
}
}
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java
index 536f6c864..c406bb5da 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WidgetManagerDelegate.java
@@ -79,4 +79,5 @@ interface WorldClickListener {
boolean isPermissionGranted(@NonNull String permission);
void requestPermission(String uri, @NonNull String permission, GeckoSession.PermissionDelegate.Callback aCallback);
void openNewWindow(@NonNull String uri);
+ WindowWidget getFocusedWindow();
}
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java
index c76651aa1..62ccb38c2 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/WindowWidget.java
@@ -22,6 +22,7 @@
import org.mozilla.gecko.util.ThreadUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
import org.mozilla.geckoview.AllowOrDeny;
import org.mozilla.geckoview.GeckoDisplay;
@@ -35,6 +36,7 @@
import org.mozilla.vrbrowser.browser.engine.SessionStack;
import org.mozilla.vrbrowser.telemetry.TelemetryWrapper;
import org.mozilla.vrbrowser.ui.views.BookmarksView;
+import org.mozilla.vrbrowser.ui.widgets.dialogs.AppDialogWidget;
import org.mozilla.vrbrowser.ui.widgets.dialogs.ContextMenuWidget;
import org.mozilla.vrbrowser.ui.widgets.dialogs.MaxWindowsWidget;
import org.mozilla.vrbrowser.ui.widgets.prompts.AlertPromptWidget;
@@ -72,6 +74,7 @@ public class WindowWidget extends UIWidget implements SessionChangeListener,
private TextPromptWidget mTextPrompt;
private AuthPromptWidget mAuthPrompt;
private NoInternetWidget mNoInternetToast;
+ private AppDialogWidget mAppDialog;
private ContextMenuWidget mContextMenu;
private int mWidthBackup;
private int mHeightBackup;
@@ -728,6 +731,26 @@ public void showButtonPrompt(String title, @NonNull String msg, @NonNull String[
mConfirmPrompt.show(REQUEST_FOCUS);
}
+ public void showAppDialog(@NonNull @StringRes int title, @NonNull @StringRes int description, @NonNull @StringRes int [] btnMsg, @NonNull AppDialogWidget.Delegate callback) {
+ mAppDialog = new AppDialogWidget(getContext());
+ mAppDialog.mWidgetPlacement.parentHandle = getHandle();
+ mAppDialog.setTitle(title);
+ mAppDialog.setMessage(description);
+ mAppDialog.setButtons(btnMsg);
+ mAppDialog.setDelegate(callback);
+ mAppDialog.show(REQUEST_FOCUS);
+ }
+
+ public void showAppDialog(@NonNull String title, @NonNull String description, @NonNull String[] btnMsg, @NonNull AppDialogWidget.Delegate callback) {
+ mAppDialog = new AppDialogWidget(getContext());
+ mAppDialog.mWidgetPlacement.parentHandle = getHandle();
+ mAppDialog.setTitle(title);
+ mAppDialog.setMessage(description);
+ mAppDialog.setButtons(btnMsg);
+ mAppDialog.setDelegate(callback);
+ mAppDialog.show(REQUEST_FOCUS);
+ }
+
public void showMaxWindowsDialog(int maxDialogs) {
mMaxWindowsDialog = new MaxWindowsWidget(getContext());
mMaxWindowsDialog.mWidgetPlacement.parentHandle = getHandle();
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/AppDialogWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/AppDialogWidget.java
new file mode 100644
index 000000000..55d8deee1
--- /dev/null
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/AppDialogWidget.java
@@ -0,0 +1,159 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.vrbrowser.ui.widgets.dialogs;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewTreeObserver;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
+import androidx.databinding.DataBindingUtil;
+
+import org.mozilla.vrbrowser.R;
+import org.mozilla.vrbrowser.databinding.AppDialogBinding;
+import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
+import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
+import org.mozilla.vrbrowser.utils.ViewUtils;
+
+public class AppDialogWidget extends UIDialog {
+
+ public interface Delegate {
+ void onButtonClicked(int index);
+ void onMessageLinkClicked(@NonNull String url);
+ }
+
+ public static final int LEFT = 0;
+ public static final int RIGHT = 1;
+
+ private AppDialogBinding mBinding;
+ private Delegate mAppDialogDelegate;
+
+ public AppDialogWidget(Context aContext) {
+ super(aContext);
+ initialize(aContext);
+ }
+
+ public AppDialogWidget(Context aContext, AttributeSet aAttrs) {
+ super(aContext, aAttrs);
+ initialize(aContext);
+ }
+
+ public AppDialogWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) {
+ super(aContext, aAttrs, aDefStyle);
+ initialize(aContext);
+ }
+
+ private void initialize(Context aContext) {
+ LayoutInflater inflater = LayoutInflater.from(aContext);
+
+ // Inflate this data binding layout
+ mBinding = DataBindingUtil.inflate(inflater, R.layout.app_dialog, this, true);
+
+ mBinding.leftButton.setOnClickListener(v -> {
+ if (mAppDialogDelegate != null)
+ mAppDialogDelegate.onButtonClicked(LEFT);
+
+ AppDialogWidget.this.onDismiss();
+ });
+ mBinding.rightButton.setOnClickListener(v -> {
+ if (mAppDialogDelegate != null)
+ mAppDialogDelegate.onButtonClicked(RIGHT);
+
+ AppDialogWidget.this.onDismiss();
+ });
+ }
+
+ @Override
+ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
+ aPlacement.visible = false;
+ aPlacement.width = WidgetPlacement.dpDimension(getContext(), R.dimen.app_dialog_width);
+ aPlacement.height = WidgetPlacement.pixelDimension(getContext(), R.dimen.browser_width_pixels)/2;
+ aPlacement.parentAnchorX = 0.5f;
+ aPlacement.parentAnchorY = 0.5f;
+ aPlacement.anchorX = 0.5f;
+ aPlacement.anchorY = 0.5f;
+ aPlacement.translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.app_dialog_z_distance);
+ }
+
+
+ @Override
+ public void show(@ShowFlags int aShowFlags) {
+ measure(View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+
+ super.show(aShowFlags);
+
+ mWidgetManager.pushWorldBrightness(this, WidgetManagerDelegate.DEFAULT_DIM_BRIGHTNESS);
+
+ ViewTreeObserver viewTreeObserver = getViewTreeObserver();
+ if (viewTreeObserver.isAlive()) {
+ viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ mWidgetPlacement.height = (int)(getHeight()/mWidgetPlacement.density);
+ mWidgetManager.updateWidget(AppDialogWidget.this);
+ }
+ });
+ }
+ }
+
+ public void hide(@HideFlags int aHideFlags) {
+ super.hide(aHideFlags);
+ mWidgetManager.popWorldBrightness(this);
+ }
+
+ // WidgetManagerDelegate.FocusChangeListener
+ @Override
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ if (oldFocus == this && isVisible() && findViewById(newFocus.getId()) == null) {
+ onDismiss();
+ }
+ }
+
+ public void setDelegate(Delegate delegate) {
+ mAppDialogDelegate = delegate;
+ }
+
+ public void setTitle(@StringRes int title) {
+ mBinding.title.setText(title);
+ }
+
+ public void setTitle(String title) {
+ mBinding.title.setText(title);
+ }
+
+ public void setMessage(@StringRes int message) {
+ ViewUtils.setTextViewHTML(mBinding.message, getResources().getString(message), (widget, url) -> {
+ if (mAppDialogDelegate != null) {
+ mAppDialogDelegate.onMessageLinkClicked(url);
+ onDismiss();
+ }
+ });
+ }
+
+ public void setMessage(String message) {
+ mBinding.message.setText(message);
+ }
+
+ public void setButtons(@StringRes int[] buttons) {
+ if (buttons.length > 0)
+ mBinding.leftButton.setText(buttons[LEFT]);
+ if (buttons.length > 1)
+ mBinding.rightButton.setText(buttons[RIGHT]);
+ }
+
+ public void setButtons(@NonNull String[] buttons) {
+ if (buttons.length > 0)
+ mBinding.leftButton.setText(buttons[LEFT]);
+ if (buttons.length > 1)
+ mBinding.rightButton.setText(buttons[RIGHT]);
+ }
+
+}
diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java
index 68aac8488..a62d501e1 100644
--- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java
+++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/dialogs/VoiceSearchWidget.java
@@ -23,15 +23,18 @@
import com.mozilla.speechlibrary.MozillaSpeechService;
import com.mozilla.speechlibrary.STTResult;
+import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.audio.AudioEngine;
import org.mozilla.vrbrowser.browser.SettingsStore;
+import org.mozilla.vrbrowser.browser.engine.SessionStore;
import org.mozilla.vrbrowser.utils.DeviceType;
import org.mozilla.vrbrowser.ui.views.UIButton;
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
import org.mozilla.vrbrowser.utils.LocaleUtils;
+import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
public class VoiceSearchWidget extends UIDialog implements WidgetManagerDelegate.PermissionListener,
@@ -90,9 +93,6 @@ private void initialize(Context aContext) {
mMozillaSpeechService = MozillaSpeechService.getInstance();
mMozillaSpeechService.setProductTag(getContext().getString(R.string.voice_app_id));
- boolean storeData = SettingsStore.getInstance(aContext).isSpeechDataCollectionEnabled();
- mMozillaSpeechService.storeSamples(storeData);
- mMozillaSpeechService.storeTranscriptions(storeData);
mVoiceSearchText1 = findViewById(R.id.voiceSearchText1);
mVoiceSearchText2 = findViewById(R.id.voiceSearchText2);
@@ -150,8 +150,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) {
aPlacement.parentAnchorY = 0.5f;
aPlacement.anchorX = 0.5f;
aPlacement.anchorY = 0.5f;
- aPlacement.translationY = WidgetPlacement.unitFromMeters(getContext(), R.dimen.restart_dialog_world_y);
- aPlacement.translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.restart_dialog_world_z);
+ aPlacement.translationZ = WidgetPlacement.unitFromMeters(getContext(), R.dimen.voice_search_world_z);
}
public void setPlacementForKeyboard(int aHandle) {
@@ -230,6 +229,11 @@ public void startVoiceSearch() {
} else {
String locale = LocaleUtils.getVoiceSearchLocale(getContext());
mMozillaSpeechService.setLanguage(LocaleUtils.mapToMozillaSpeechLocales(locale));
+ boolean storeData = SettingsStore.getInstance(getContext()).isSpeechDataCollectionEnabled();
+ if (SessionStore.get().getActiveStore().isPrivateMode())
+ storeData = false;
+ mMozillaSpeechService.storeSamples(storeData);
+ mMozillaSpeechService.storeTranscriptions(storeData);
mMozillaSpeechService.start(getContext().getApplicationContext());
mIsSpeechRecognitionRunning = true;
}
@@ -269,11 +273,37 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions, in
@Override
public void show(@ShowFlags int aShowFlags) {
- super.show(aShowFlags);
+ if (SettingsStore.getInstance(getContext()).isSpeechDataCollectionReviewed()) {
+ super.show(aShowFlags);
- setStartListeningState();
+ setStartListeningState();
- startVoiceSearch();
+ startVoiceSearch();
+
+ } else {
+ mWidgetManager.getFocusedWindow().showAppDialog(
+ R.string.voice_samples_collect_dialog_title,
+ R.string.voice_samples_collect_dialog_description,
+ new int[]{
+ R.string.voice_samples_collect_dialog_do_not_allow,
+ R.string.voice_samples_collect_dialog_allow},
+ new AppDialogWidget.Delegate() {
+ @Override
+ public void onButtonClicked(int index) {
+ SettingsStore.getInstance(getContext()).setSpeechDataCollectionReviewed(true);
+ if (index == AppDialogWidget.RIGHT) {
+ SettingsStore.getInstance(getContext()).setSpeechDataCollectionEnabled(true);
+ }
+ ThreadUtils.postToUiThread(() -> show(aShowFlags));
+ }
+
+ @Override
+ public void onMessageLinkClicked(@NonNull String url) {
+ mWidgetManager.getFocusedWindow().getSessionStack().loadUri(getResources().getString(R.string.private_policy_url));
+ onDismiss();
+ }
+ });
+ }
}
@Override
diff --git a/app/src/main/res/layout/app_dialog.xml b/app/src/main/res/layout/app_dialog.xml
new file mode 100644
index 000000000..29b8e30ff
--- /dev/null
+++ b/app/src/main/res/layout/app_dialog.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml
index 0fc1143e2..a4690f8c5 100644
--- a/app/src/main/res/values/dimen.xml
+++ b/app/src/main/res/values/dimen.xml
@@ -138,7 +138,7 @@
20dp
25dp
30dp
- - 0.042
+ - 2
305dp
@@ -233,4 +233,8 @@
585dp
420dp
+
+
+ 420dp
+ - 2
\ No newline at end of file
diff --git a/app/src/main/res/values/non_L10n.xml b/app/src/main/res/values/non_L10n.xml
index e8dd5c75f..c1c3f8a47 100644
--- a/app/src/main/res/values/non_L10n.xml
+++ b/app/src/main/res/values/non_L10n.xml
@@ -16,6 +16,7 @@
settings_key_drm_playback
settings_tracking_protection
settings_key_speech_data_collection
+ settings_key_speech_data_collection_accept
settings_user_agent_version
settings_touch_mode
settings_display_density
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 467bb8c58..5409c2f4d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -851,4 +851,20 @@
Default
+
+
+ Allow Firefox to Collect Voice Samples?
+
+
+ Please help Mozilla improve Firefox Reality. In order to improve our voice recognition services, we need to collect samples for research. Don’t worry, your data is protected and will always be anonymous. You can change your decision in SETTINGS. You can use Voice Search feature no matter what your decision is. <a href="privacy">Learn More</a>
+
+
+ Allow
+
+
+ Don’t Allow