Skip to content

Commit

Permalink
Merge branch 'master' of github.com:MozillaReality/FirefoxReality
Browse files Browse the repository at this point in the history
  • Loading branch information
kearwood committed Dec 19, 2019
2 parents 34c8961 + c7f86ed commit 06de613
Show file tree
Hide file tree
Showing 87 changed files with 1,156 additions and 2,375 deletions.
1 change: 1 addition & 0 deletions .taskcluster.yml
Expand Up @@ -43,6 +43,7 @@ tasks:
&& rm -rf gvr-android-sdk && git clone https://github.com/MozillaReality/FirefoxReality-gvr-android-sdk.git gvr-android-sdk
&& git submodule update
&& ./gradlew --no-daemon --console=plain clean `python tools/taskcluster/build_targets.py =all+googlevr+noapi`
&& ./gradlew app:testNoapiArm64DebugUnitTest
metadata:
name: Firefox Reality for Android - Build - Pull Request
description: Building Firefox Reality for Android (via Gradle) - triggered by a pull request.
Expand Down
18 changes: 13 additions & 5 deletions app/build.gradle
Expand Up @@ -414,6 +414,10 @@ android {
]
}
}

testOptions {
unitTests.includeAndroidResources = true
}
}

configurations {
Expand Down Expand Up @@ -460,21 +464,18 @@ dependencies {
implementation deps.android_components.support_rustlog
implementation deps.android_components.support_rusthttp
implementation deps.android_components.glean
implementation deps.app_services.rustlog

// For production builds, the native code for all `org.mozilla.appservices`
// dependencies gets compiled together into a single "megazord" build, and
// different megazords are published for different subsets of features. Ref
// https://mozilla.github.io/application-services/docs/applications/consuming-megazord-libraries.html
// For now we can jut use the one that's specifically designed for Fenix.
implementation deps.app_services.megazord
testImplementation deps.app_services.megazord_forUnitTests
modules {
module('org.mozilla.appservices:full-megazord') {
replacedBy('org.mozilla.appservices:fenix-megazord', 'prefer the fenix megazord, to reduce final application size')
}
module('org.mozilla.appservices:fenix-megazord') {
replacedBy('org.mozilla.appservices:fenix-megazord-forUnitTests', 'prefer the forUnitTests variant if present')
}
}

// TODO this should not be necessary at all, see Services.kt
Expand All @@ -495,9 +496,16 @@ dependencies {
implementation deps.disklrucache.disklrucache

// Testing
testImplementation deps.junit
androidTestImplementation deps.atsl.runner
androidTestImplementation deps.espresso.core
testImplementation deps.junit
testImplementation deps.atsl.core
testImplementation deps.robolectric
testImplementation deps.app_services.megazord_forUnitTests
testImplementation deps.app_services.rustlog
testImplementation deps.android_components.support_test
testImplementation deps.telemetry.glean_unittests
testImplementation deps.work.testing

// Daydream
googlevrImplementation deps.google_vr.sdk_base
Expand Down
111 changes: 14 additions & 97 deletions app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java
Expand Up @@ -36,9 +36,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.geckoview.CrashReporter;
import org.mozilla.geckoview.GeckoResult;
import org.mozilla.geckoview.GeckoRuntime;
import org.mozilla.geckoview.GeckoSession;
import org.mozilla.geckoview.GeckoVRManager;
Expand All @@ -62,15 +59,15 @@
import org.mozilla.vrbrowser.ui.widgets.TrayWidget;
import org.mozilla.vrbrowser.ui.widgets.UISurfaceTextureRenderer;
import org.mozilla.vrbrowser.ui.widgets.UIWidget;
import org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget;
import org.mozilla.vrbrowser.ui.widgets.Widget;
import org.mozilla.vrbrowser.ui.widgets.WidgetManagerDelegate;
import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement;
import org.mozilla.vrbrowser.ui.widgets.WindowWidget;
import org.mozilla.vrbrowser.ui.widgets.Windows;
import org.mozilla.vrbrowser.ui.widgets.dialogs.CrashDialogWidget;
import org.mozilla.vrbrowser.ui.widgets.dialogs.PromptDialogWidget;
import org.mozilla.vrbrowser.ui.widgets.dialogs.WhatsNewWidget;
import org.mozilla.vrbrowser.ui.widgets.prompts.ConfirmPromptWidget;
import org.mozilla.vrbrowser.ui.widgets.menus.VideoProjectionMenuWidget;
import org.mozilla.vrbrowser.utils.BitmapCache;
import org.mozilla.vrbrowser.utils.ConnectivityReceiver;
import org.mozilla.vrbrowser.utils.ConnectivityReceiver.Delegate;
Expand All @@ -79,13 +76,6 @@
import org.mozilla.vrbrowser.utils.ServoUtils;
import org.mozilla.vrbrowser.utils.SystemUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand Down Expand Up @@ -127,7 +117,6 @@ public void run() {
static final int GestureSwipeRight = 1;
static final int SwipeDelay = 1000; // milliseconds
static final long RESET_CRASH_COUNT_DELAY = 5000;
static final String CRASH_STATS_URL = "https://crash-stats.mozilla.com/report/index/";

static final String LOGTAG = SystemUtils.createLogtag(VRBrowserActivity.class);
HashMap<Integer, Widget> mWidgets;
Expand Down Expand Up @@ -230,7 +219,7 @@ protected void onCreate(Bundle savedInstanceState) {
// Create broadcast receiver for getting crash messages from crash process
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(CrashReporterService.CRASH_ACTION);
registerReceiver(mCrashReceiver, intentFilter, getString(R.string.app_permission_name), null);
registerReceiver(mCrashReceiver, intentFilter, BuildConfig.APPLICATION_ID + "." + getString(R.string.app_permission_name), null);

mLastGesture = NoGesture;
super.onCreate(savedInstanceState);
Expand Down Expand Up @@ -594,27 +583,12 @@ private void checkForCrash() {
}
boolean isCrashReportingEnabled = SettingsStore.getInstance(this).isCrashReportingEnabled();
if (isCrashReportingEnabled) {
postCrashFiles(files);
SystemUtils.postCrashFiles(this, files);

} else {
if (mCrashDialog == null) {
mCrashDialog = new CrashDialogWidget(this);
mCrashDialog = new CrashDialogWidget(this, files);
}
mCrashDialog.setCrashDialogDelegate(
new CrashDialogWidget.CrashDialogDelegate() {
@Override
public void onSendData() {
postCrashFiles(files);
}

@Override
public void onDoNotSendData() {
for (String file : files) {
Log.e(LOGTAG, "Deleting crashfile: " + file);
getBaseContext().deleteFile(file);
}
}
}
);
mCrashDialog.show(UIWidget.REQUEST_FOCUS);
}
}
Expand All @@ -629,65 +603,16 @@ private void handleContentCrashIntent(@NonNull final Intent intent) {

boolean isCrashReportingEnabled = SettingsStore.getInstance(this).isCrashReportingEnabled();
if (isCrashReportingEnabled) {
postCrashFiles(dumpFile, extraFile);
SystemUtils.postCrashFiles(this, dumpFile, extraFile);

} else {
if (mCrashDialog == null) {
mCrashDialog = new CrashDialogWidget(this);
mCrashDialog = new CrashDialogWidget(this, dumpFile, extraFile);
}
mCrashDialog.setCrashDialogDelegate(() -> postCrashFiles(dumpFile, extraFile));
mCrashDialog.show(UIWidget.REQUEST_FOCUS);
}
}

private void sendCrashFiles(@NonNull final String aDumpFile, @NonNull final String aExtraFile) {
try {
GeckoResult<String> result = CrashReporter.sendCrashReport(VRBrowserActivity.this, new File(aDumpFile), new File(aExtraFile), getString(R.string.crash_app_name));

result.accept(crashID -> {
Log.e(LOGTAG, "Submitted crash report id: " + crashID);
Log.e(LOGTAG, "Report available at: " + CRASH_STATS_URL + crashID);
}, ex -> {
Log.e(LOGTAG, "Failed to submit crash report: " + (ex != null ? ex.getMessage() : "Exception is NULL"));
});
} catch (IOException | URISyntaxException e) {
Log.e(LOGTAG, "Failed to send crash report: " + e.toString());
}
}

private void postCrashFiles(@NonNull final String aDumpFile, @NonNull final String aExtraFile) {
ThreadUtils.postToBackgroundThread(() -> {
sendCrashFiles(aDumpFile, aExtraFile);
});
}

private void postCrashFiles(final ArrayList<String> aFiles) {
ThreadUtils.postToBackgroundThread(() -> {
for (String file: aFiles) {
try {
ArrayList<String> list = new ArrayList<>(2);
try (FileInputStream in = getBaseContext().openFileInput(file)) {
try(BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
String line;
while((line = br.readLine()) != null) {
list.add(line);
}
}
} catch (IOException e) {
e.printStackTrace();
}
if (list.size() < 2) {
Log.e(LOGTAG, "Failed read crash dump file names from: " + file);
return;
}
sendCrashFiles(list.get(0), list.get(1));
} finally {
Log.d(LOGTAG,"Removing crash file: " + file);
getBaseContext().deleteFile(file);
}
}
});
}

@Override
public void onTrimMemory(int level) {

Expand Down Expand Up @@ -1109,7 +1034,7 @@ private void haltActivity(final int aReason) {
mWindows.getFocusedWindow().showAlert(
getString(R.string.not_entitled_title),
getString(R.string.not_entitled_message, getString(R.string.app_name)),
() -> VRBrowserActivity.this.finish());
index -> finish());
}
});
}
Expand All @@ -1135,18 +1060,10 @@ private void handlePoorPerformance() {
}
window.getSession().loadHomePage();
final String[] buttons = {getString(R.string.ok_button), getString(R.string.performance_unblock_page)};
window.showButtonPrompt(getString(R.string.performance_title), getString(R.string.performance_message), buttons, new ConfirmPromptWidget.ConfirmPromptDelegate() {
@Override
public void confirm(int index) {
if (index == GeckoSession.PromptDelegate.ButtonPrompt.Type.NEGATIVE) {
mPoorPerformanceWhiteList.add(originalUri);
window.getSession().loadUri(originalUri);
}
}

@Override
public void dismiss() {

window.showConfirmPrompt(getString(R.string.performance_title), getString(R.string.performance_message), buttons, index -> {
if (index == PromptDialogWidget.NEGATIVE) {
mPoorPerformanceWhiteList.add(originalUri);
window.getSession().loadUri(originalUri);
}
});
});
Expand Down
Expand Up @@ -229,7 +229,12 @@ class Accounts constructor(val context: Context) {

private fun loadDefaultProfilePicture(): BitmapDrawable? {
BitmapFactory.decodeResource(context.resources, R.drawable.ic_icon_settings_account)?.let {
BitmapCache.getInstance(context).addBitmap(PROFILE_PICTURE_TAG, it)
try {
BitmapCache.getInstance(context).addBitmap(PROFILE_PICTURE_TAG, it)
} catch (e: NullPointerException) {
Log.w(LOGTAG, "Bitmap is a null pointer.")
return null
}
profilePicture = BitmapDrawable(context.resources, ViewUtils.getRoundedCroppedBitmap(it))
}

Expand Down
Expand Up @@ -68,7 +68,6 @@ public void handlePermission(final String aUri, final PermissionWidget.Permissio
mWidgetManager.addWidget(mPermissionWidget);
}

mPermissionWidget.getPlacement().parentHandle = mParentWidgetHandle;
mPermissionWidget.showPrompt(aUri, aType, aCallback);
}

Expand Down
Expand Up @@ -132,7 +132,7 @@ public GeckoResult<PromptResponse> onAlertPrompt(@NonNull GeckoSession geckoSess
mPrompt = new AlertPromptWidget(mContext);
mPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPrompt.getPlacement().parentAnchorY = 0.0f;
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.js_prompt_y_distance);
mPrompt.setTitle(alertPrompt.title);
mPrompt.setMessage(alertPrompt.message);
mPrompt.setPromptDelegate(() -> result.complete(alertPrompt.dismiss()));
Expand All @@ -149,7 +149,7 @@ public GeckoResult<PromptResponse> onButtonPrompt(@NonNull GeckoSession geckoSes
mPrompt = new ConfirmPromptWidget(mContext);
mPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPrompt.getPlacement().parentAnchorY = 0.0f;
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.js_prompt_y_distance);
mPrompt.setTitle(buttonPrompt.title);
mPrompt.setMessage(buttonPrompt.message);
((ConfirmPromptWidget)mPrompt).setButtons(new String[] {
Expand Down Expand Up @@ -180,7 +180,7 @@ public GeckoResult<PromptResponse> onTextPrompt(@NonNull GeckoSession geckoSessi
mPrompt = new TextPromptWidget(mContext);
mPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPrompt.getPlacement().parentAnchorY = 0.0f;
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.js_prompt_y_distance);
mPrompt.setTitle(textPrompt.title);
mPrompt.setMessage(textPrompt.message);
((TextPromptWidget)mPrompt).setDefaultText(textPrompt.defaultValue);
Expand Down Expand Up @@ -208,7 +208,7 @@ public GeckoResult<PromptResponse> onAuthPrompt(@NonNull GeckoSession geckoSessi
mPrompt = new AuthPromptWidget(mContext);
mPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPrompt.getPlacement().parentAnchorY = 0.0f;
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.js_prompt_y_distance);
mPrompt.setTitle(authPrompt.title);
mPrompt.setMessage(authPrompt.message);
((AuthPromptWidget)mPrompt).setAuthOptions(authPrompt.authOptions);
Expand Down Expand Up @@ -241,7 +241,7 @@ public GeckoResult<PromptResponse> onChoicePrompt(@NonNull GeckoSession geckoSes
mPrompt = new ChoicePromptWidget(mContext);
mPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPrompt.getPlacement().parentAnchorY = 0.0f;
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.js_prompt_y_distance);
mPrompt.setTitle(choicePrompt.title);
mPrompt.setMessage(choicePrompt.message);
((ChoicePromptWidget)mPrompt).setChoices(choicePrompt.choices);
Expand Down Expand Up @@ -352,10 +352,6 @@ private void showPopUp(int sessionId, @NonNull Pair<String, LinkedList<PopUpRequ
Optional<PopUpSite> site = mAllowedPopUpSites.stream().filter((item) -> item.url.equals(uri)).findFirst();
if (!site.isPresent()) {
mPopUpPrompt = new PopUpBlockDialogWidget(mContext);
mPopUpPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mPopUpPrompt.getPlacement().parentAnchorY = 0.0f;
mPopUpPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mPopUpPrompt.setTitle(uri);
mPopUpPrompt.setButtonsDelegate(index -> {
boolean allowed = index != PopUpBlockDialogWidget.NEGATIVE;
boolean askAgain = mPopUpPrompt.askAgain();
Expand Down Expand Up @@ -384,7 +380,14 @@ private void showPopUp(int sessionId, @NonNull Pair<String, LinkedList<PopUpRequ
}
});
}

mPopUpPrompt.hide(UIWidget.REMOVE_WIDGET);
});
mPopUpPrompt.setDelegate(() -> mExecutors.mainThread().execute(() -> {
if (mPopupDelegate != null) {
mPopupDelegate.onPopUpAvailable();
}
}));
mPopUpPrompt.show(UIWidget.REQUEST_FOCUS);

} else {
Expand All @@ -407,7 +410,7 @@ public GeckoResult<SlowScriptResponse> onSlowScript(@NonNull GeckoSession aSessi
mSlowScriptPrompt = new ConfirmPromptWidget(mContext);
mSlowScriptPrompt.getPlacement().parentHandle = mAttachedWindow.getHandle();
mSlowScriptPrompt.getPlacement().parentAnchorY = 0.0f;
mSlowScriptPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.base_app_dialog_y_distance);
mSlowScriptPrompt.getPlacement().translationY = WidgetPlacement.unitFromMeters(mContext, R.dimen.js_prompt_y_distance);
mSlowScriptPrompt.setTitle(mContext.getResources().getString(R.string.slow_script_dialog_title));
mSlowScriptPrompt.setMessage(mContext.getResources().getString(R.string.slow_script_dialog_description, aScriptFileName));
mSlowScriptPrompt.setButtons(new String[]{
Expand Down
Expand Up @@ -15,6 +15,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.appservices.Megazord
import mozilla.appservices.rustlog.LogAdapterCannotEnable
import mozilla.components.concept.sync.*
import mozilla.components.service.fxa.*
import mozilla.components.service.fxa.manager.FxaAccountManager
Expand All @@ -29,8 +30,6 @@ import org.mozilla.geckoview.GeckoResult
import org.mozilla.geckoview.GeckoSession
import org.mozilla.vrbrowser.R
import org.mozilla.vrbrowser.browser.engine.EngineProvider
import org.mozilla.vrbrowser.browser.engine.GeckoViewFetchClient
import org.mozilla.vrbrowser.browser.engine.SessionStore
import org.mozilla.vrbrowser.utils.SystemUtils
import org.mozilla.vrbrowser.telemetry.GleanMetricsService

Expand All @@ -52,7 +51,11 @@ class Services(val context: Context, places: Places): GeckoSession.NavigationDel
// This makes bookmarks storage accessible to background sync workers.
init {
Megazord.init()
RustLog.enable()
try {
RustLog.enable()
} catch (e: LogAdapterCannotEnable) {
android.util.Log.w(LOGTAG, "RustLog has been enabled.")
}
RustHttpConfig.setClient(lazy { EngineProvider.createClient(context) })

// Make sure we get logs out of our android-components.
Expand Down

0 comments on commit 06de613

Please sign in to comment.