diff --git a/app/build.gradle b/app/build.gradle index 876a7e986a..d172366d89 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,16 +18,16 @@ def getCrashRestartDisabled = { -> } android { - compileSdkVersion 27 + compileSdkVersion build_versions.target_sdk defaultConfig { applicationId "org.mozilla.vrbrowser" - minSdkVersion 24 - targetSdkVersion 27 + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk versionCode 1 versionName "1.1" buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\"" buildConfigField "Boolean", "DISABLE_CRASH_RESTART", getCrashRestartDisabled() - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" externalNativeBuild { cmake { cppFlags "-std=c++14 -fexceptions -frtti -Werror" + @@ -36,6 +36,12 @@ android { arguments "-DANDROID_STL=c++_shared" } } + + javaCompileOptions { + annotationProcessorOptions { + arguments = ["room.schemaLocation": "$projectDir/schemas".toString()] + } + } } if (gradle.hasProperty('taskclusterBuild')) { @@ -44,22 +50,29 @@ android { } else { project.archivesBaseName = "FirefoxReality" } + compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } + buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + externalNativeBuild { cmake { path "CMakeLists.txt" } } + dataBinding { + enabled = true + } + lintOptions { disable "LogUsage", "ExtraTranslation" } @@ -83,17 +96,6 @@ android { } } - googlevrFlat { - dimension "platform" - externalNativeBuild { - cmake { - cppFlags " -I" + file("${project.rootDir}/gvr-android-sdk/libraries/headers").absolutePath + - " -DVRBROWSER_GOOGLEVR" - arguments "-DVR_SDK_LIB=googlevr-lib", "-DGOOGLEVR=ON" - } - } - } - oculusvr { dimension "platform" externalNativeBuild { @@ -185,13 +187,6 @@ android { ] } - googlevrFlat { - java.srcDirs = [ - 'src/googlevr/java', - 'src/googlevrFlat/java' - ] - } - oculusvr { java.srcDirs = [ 'src/oculusvr/java' @@ -232,27 +227,32 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') // Common - implementation 'com.android.support:appcompat-v7:27.1.1' - implementation 'com.android.support.constraint:constraint-layout:1.1.3' - implementation 'com.android.support:design:27.1.1' - implementation 'com.google.vr:sdk-audio:1.170.0' + implementation deps.google_vr.sdk_audio + implementation deps.room.runtime + annotationProcessor deps.room.compiler + implementation deps.lifecycle.runtime + implementation deps.lifecycle.extensions + implementation deps.support.cardview + implementation deps.support.app_compat + implementation deps.support.annotations + implementation deps.constraint_layout // Android Components - implementation "com.github.mozilla:mozillaspeechlibrary:1.0.6" - implementation "org.mozilla.components:service-telemetry:${rootProject.ext.androidComponents['version']}" - implementation "org.mozilla.components:browser-errorpages:${rootProject.ext.androidComponents['version']}" - implementation "org.mozilla.components:browser-search:${rootProject.ext.androidComponents['version']}" - implementation "org.mozilla.components:browser-domains:${rootProject.ext.androidComponents['version']}" - implementation "org.mozilla.components:ui-autocomplete:${rootProject.ext.androidComponents['version']}" + implementation deps.mozilla_speech + implementation deps.android_components.telemetry + implementation deps.android_components.browser_errorpages + implementation deps.android_components.browser_search + implementation deps.android_components.browser_domains + implementation deps.android_components.ui_autocomplete // Testing - testImplementation 'junit:junit:4.12' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + testImplementation deps.junit + androidTestImplementation deps.atsl.runner + androidTestImplementation deps.espresso.core + testImplementation deps.room.testing // Daydream - googlevrImplementation 'com.google.vr:sdk-base:1.170.0' - googlevrFlatImplementation 'com.google.vr:sdk-base:1.170.0' + googlevrImplementation deps.google_vr.sdk_base // ODG svrImplementation fileTree(dir: "${project.rootDir}/third_party/svr/", include: ['*.jar']) @@ -279,8 +279,8 @@ if (findProject(':geckoview-local')) { dependencies { // To see what the latest geckoview-nightly version is go here: // https://maven.mozilla.org/?prefix=maven2/org/mozilla/geckoview/geckoview-nightly-armeabi-v7a/ - armImplementation "org.mozilla.geckoview:geckoview-nightly-armeabi-v7a:${rootProject.ext.geckoNightly['version']}" - x86Implementation "org.mozilla.geckoview:geckoview-nightly-x86:${rootProject.ext.geckoNightly['version']}" + armImplementation deps.gecko_view.nightly + x86Implementation deps.gecko_view.nightly } } diff --git a/app/schemas/org.mozilla.vrbrowser.db.AppDatabase/1.json b/app/schemas/org.mozilla.vrbrowser.db.AppDatabase/1.json new file mode 100644 index 0000000000..24176d40b9 --- /dev/null +++ b/app/schemas/org.mozilla.vrbrowser.db.AppDatabase/1.json @@ -0,0 +1,61 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "73fd28ddd217ef5521de7dd6874b45ce", + "entities": [ + { + "tableName": "bookmarks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `url` TEXT, `timestamp` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_bookmarks_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX `index_bookmarks_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"73fd28ddd217ef5521de7dd6874b45ce\")" + ] + } +} \ No newline at end of file diff --git a/app/schemas/org.mozilla.vrbrowser.db.BookmarkDatabase/1.json b/app/schemas/org.mozilla.vrbrowser.db.BookmarkDatabase/1.json new file mode 100644 index 0000000000..24176d40b9 --- /dev/null +++ b/app/schemas/org.mozilla.vrbrowser.db.BookmarkDatabase/1.json @@ -0,0 +1,61 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "73fd28ddd217ef5521de7dd6874b45ce", + "entities": [ + { + "tableName": "bookmarks", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `title` TEXT, `url` TEXT, `timestamp` INTEGER NOT NULL)", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "id" + ], + "autoGenerate": true + }, + "indices": [ + { + "name": "index_bookmarks_url", + "unique": true, + "columnNames": [ + "url" + ], + "createSql": "CREATE UNIQUE INDEX `index_bookmarks_url` ON `${TABLE_NAME}` (`url`)" + } + ], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"73fd28ddd217ef5521de7dd6874b45ce\")" + ] + } +} \ No newline at end of file diff --git a/app/src/common/shared/org/mozilla/vrbrowser/AppExecutors.java b/app/src/common/shared/org/mozilla/vrbrowser/AppExecutors.java new file mode 100644 index 0000000000..b34e247907 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/AppExecutors.java @@ -0,0 +1,50 @@ +package org.mozilla.vrbrowser; + +import android.os.Handler; +import android.os.Looper; + +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; + +import androidx.annotation.NonNull; + +public class AppExecutors { + + private final Executor mDiskIO; + + private final Executor mNetworkIO; + + private final Executor mMainThread; + + private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) { + this.mDiskIO = diskIO; + this.mNetworkIO = networkIO; + this.mMainThread = mainThread; + } + + public AppExecutors() { + this(Executors.newSingleThreadExecutor(), Executors.newFixedThreadPool(3), + new MainThreadExecutor()); + } + + public Executor diskIO() { + return mDiskIO; + } + + public Executor networkIO() { + return mNetworkIO; + } + + public Executor mainThread() { + return mMainThread; + } + + private static class MainThreadExecutor implements Executor { + private Handler mainThreadHandler = new Handler(Looper.getMainLooper()); + + @Override + public void execute(@NonNull Runnable command) { + mainThreadHandler.post(command); + } + } +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/DataRepository.java b/app/src/common/shared/org/mozilla/vrbrowser/DataRepository.java new file mode 100644 index 0000000000..4d29aa2b31 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/DataRepository.java @@ -0,0 +1,64 @@ +package org.mozilla.vrbrowser; + +import org.mozilla.vrbrowser.db.AppDatabase; +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; +import org.mozilla.vrbrowser.model.Bookmark; + +import java.util.List; +import java.util.function.Function; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MediatorLiveData; + +public class DataRepository { + + private static DataRepository sInstance; + + private final AppExecutors mExecutors; + private final AppDatabase mDatabase; + private MediatorLiveData> mObservableBookmark; + + private DataRepository(final AppDatabase database, final AppExecutors executors) { + mDatabase = database; + mExecutors = executors; + mObservableBookmark = new MediatorLiveData<>(); + + mObservableBookmark.addSource(mDatabase.bookmarkDao().loadAllBookmarks(), + bookmarkEntities -> { + if (mDatabase.getDatabaseCreated().getValue() != null) { + mObservableBookmark.postValue(bookmarkEntities); + } + }); + } + + public static DataRepository getInstance(final AppDatabase database, final AppExecutors executors) { + if (sInstance == null) { + synchronized (DataRepository.class) { + if (sInstance == null) { + sInstance = new DataRepository(database, executors); + } + } + } + return sInstance; + } + + public LiveData> getBookmarks() { + return mObservableBookmark; + } + + public LiveData getBookmarkByUrl(final String url) { + return mDatabase.bookmarkDao().getBookmarkByUrlAsync(url); + } + + public void insertBookmark(BookmarkEntity bookmark) { + mExecutors.diskIO().execute(() -> mDatabase.bookmarkDao().insertBookmark(bookmark)); + } + + public void deleteBookmark(Bookmark bookmark) { + mExecutors.diskIO().execute(() -> mDatabase.bookmarkDao().deleteById(bookmark.getId())); + } + + public void deleteBookmarkByUrl(String url) { + mExecutors.diskIO().execute(() -> mDatabase.bookmarkDao().deleteByUrl(url)); + } +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java index 0aab56079d..6400dc9b93 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserActivity.java @@ -16,8 +16,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.support.annotation.Keep; -import android.support.annotation.NonNull; import android.util.Log; import android.util.Pair; import android.view.KeyEvent; @@ -41,6 +39,8 @@ import org.mozilla.vrbrowser.search.SearchEngineWrapper; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; import org.mozilla.vrbrowser.ui.OffscreenDisplay; +import org.mozilla.vrbrowser.ui.widgets.BookmarkListener; +import org.mozilla.vrbrowser.ui.widgets.BookmarksWidget; import org.mozilla.vrbrowser.ui.widgets.BrowserWidget; import org.mozilla.vrbrowser.ui.widgets.CrashDialogWidget; import org.mozilla.vrbrowser.ui.widgets.KeyboardWidget; @@ -59,6 +59,9 @@ import java.util.HashMap; import java.util.LinkedList; +import androidx.annotation.Keep; +import androidx.annotation.NonNull; + public class VRBrowserActivity extends PlatformActivity implements WidgetManagerDelegate { private BroadcastReceiver mCrashReceiver = new BroadcastReceiver() { @@ -108,6 +111,7 @@ public void run() { CrashDialogWidget mCrashDialog; TopBarWidget mTopBar; TrayWidget mTray; + BookmarksWidget mBookmarksWidget; PermissionDelegate mPermissionDelegate; LinkedList mWidgetUpdateListeners; LinkedList mPermissionListeners; @@ -214,7 +218,17 @@ protected void initializeWorld() { // Create Tray mTray = new TrayWidget(this); - addWidgets(Arrays.asList(mRootWidget, mBrowserWidget, mNavigationBar, mKeyboard, mTray)); + + // Bookmarks panel + mBookmarksWidget = new BookmarksWidget(this); + mBookmarksWidget.setBrowserWidget(mBrowserWidget); + + // Add widget listeners + mTray.addListener(mBookmarksWidget); + mBookmarksWidget.addListeners(new BookmarkListener[]{mBrowserWidget, mNavigationBar, mTray}); + mNavigationBar.addListener(mBookmarksWidget); + + addWidgets(Arrays.asList(mRootWidget, mBrowserWidget, mNavigationBar, mKeyboard, mTray, mBookmarksWidget)); } @Override @@ -268,6 +282,11 @@ protected void onDestroy() { mPermissionDelegate.release(); } + // Remove all widget listeners + mTray.removeAllListeners(); + mBookmarksWidget.removeAllListeners(); + mNavigationBar.removeAllListeners(); + SessionStore.get().unregisterListeners(); super.onDestroy(); } @@ -814,7 +833,7 @@ public void setControllersVisible(final boolean aVisible) { @Override public void setBrowserSize(float targetWidth, float targetHeight) { - mBrowserWidget.setBrowserSize(targetWidth, targetHeight, 1.0f); + mBrowserWidget.setSize(targetWidth, targetHeight, 1.0f); } @Override diff --git a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java index 32883acff0..3badef3fb8 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/VRBrowserApplication.java @@ -7,12 +7,27 @@ import android.app.Application; +import org.mozilla.vrbrowser.db.AppDatabase; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; public class VRBrowserApplication extends Application { + + private AppExecutors mAppExecutors; + @Override public void onCreate() { super.onCreate(); + + mAppExecutors = new AppExecutors(); + TelemetryWrapper.init(this); } + + public AppDatabase getDatabase() { + return AppDatabase.getInstance(this, mAppExecutors); + } + + public DataRepository getRepository() { + return DataRepository.getInstance(getDatabase(), mAppExecutors); + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java index 5f7059b040..a9a3ae29b0 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/Media.java @@ -1,11 +1,10 @@ package org.mozilla.vrbrowser.browser; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.util.Log; - import org.mozilla.geckoview.MediaElement; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + public class Media implements MediaElement.Delegate { private static final String LOGTAG = "VRB"; private boolean mIsFullscreen = false; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java index c6a16ba987..a6497f2f43 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/PermissionDelegate.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; -import android.support.annotation.NonNull; import android.util.Log; import org.mozilla.geckoview.GeckoSession; @@ -16,6 +15,8 @@ import java.util.ArrayList; import java.util.Arrays; +import androidx.annotation.NonNull; + public class PermissionDelegate implements GeckoSession.PermissionDelegate, WidgetManagerDelegate.PermissionListener { static final int PERMISSION_REQUEST_CODE = 1143; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/browser/SessionStore.java b/app/src/common/shared/org/mozilla/vrbrowser/browser/SessionStore.java index 579342fd18..92a3222ff8 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/SessionStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/SessionStore.java @@ -10,8 +10,6 @@ import android.graphics.Rect; import android.os.Bundle; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.Log; import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.ExtractedText; @@ -50,6 +48,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import static org.mozilla.vrbrowser.utils.ServoUtils.createServoSession; import static org.mozilla.vrbrowser.utils.ServoUtils.isInstanceOfServoSession; import static org.mozilla.vrbrowser.utils.ServoUtils.isServoAvailable; @@ -491,6 +492,18 @@ public String getCurrentUri() { return result; } + public String getCurrentTitle() { + String result = ""; + if (mCurrentSession != null) { + State state = mSessions.get(mCurrentSession.hashCode()); + if (state == null) { + return result; + } + result = state.mTitle; + } + return result; + } + public String getPreviousUri() { String result = ""; if (mCurrentSession != null) { @@ -879,19 +892,15 @@ public void onCanGoForward(GeckoSession aSession, boolean aCanGoForward) { AtomicBoolean allowed = new AtomicBoolean(false); for (GeckoSession.NavigationDelegate listener: mNavigationListeners) { GeckoResult listenerResult = listener.onLoadRequest(aSession, aRequest); - listenerResult.then(new GeckoResult.OnValueListener() { - @Nullable - @Override - public GeckoResult onValue(@Nullable AllowOrDeny value) { - if (AllowOrDeny.ALLOW.equals(value)) { - allowed.set(true); - } - if (count.getAndIncrement() == mNavigationListeners.size() - 1) { - result.complete(allowed.get() ? AllowOrDeny.ALLOW : AllowOrDeny.DENY); - } - - return null; + listenerResult.then(value -> { + if (AllowOrDeny.ALLOW.equals(value)) { + allowed.set(true); } + if (count.getAndIncrement() == mNavigationListeners.size() - 1) { + result.complete(allowed.get() ? AllowOrDeny.ALLOW : AllowOrDeny.DENY); + } + + return null; }); } } 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 9ce2c3d456..27877b3a44 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/browser/SettingsStore.java @@ -5,13 +5,14 @@ import android.graphics.Color; import android.os.StrictMode; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; import org.mozilla.geckoview.GeckoSessionSettings; import org.mozilla.telemetry.TelemetryHolder; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; +import androidx.annotation.NonNull; + import static org.mozilla.vrbrowser.utils.ServoUtils.isServoAvailable; public class SettingsStore { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/CrashReporterService.java b/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/CrashReporterService.java index b376ddc1ad..469f8e9965 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/CrashReporterService.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/CrashReporterService.java @@ -5,8 +5,6 @@ import android.content.Intent; import android.os.Build; import android.os.Process; -import android.support.annotation.NonNull; -import android.support.v4.app.JobIntentService; import android.util.Log; import org.mozilla.geckoview.GeckoRuntime; @@ -14,6 +12,9 @@ import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.VRBrowserActivity; +import androidx.annotation.NonNull; +import androidx.core.app.JobIntentService; + public class CrashReporterService extends JobIntentService { private static final String LOGTAG = "VRB"; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/GlobalExceptionHandler.java b/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/GlobalExceptionHandler.java index 58b9ebab52..97c79d6fb4 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/GlobalExceptionHandler.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/crashreporting/GlobalExceptionHandler.java @@ -1,10 +1,11 @@ package org.mozilla.vrbrowser.crashreporting; -import android.support.annotation.NonNull; import android.util.Log; import org.mozilla.gecko.CrashHandler; +import androidx.annotation.NonNull; + public class GlobalExceptionHandler { private static final String LOGTAG = "VRB"; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/db/AppDatabase.java b/app/src/common/shared/org/mozilla/vrbrowser/db/AppDatabase.java new file mode 100644 index 0000000000..7cc86a0834 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/db/AppDatabase.java @@ -0,0 +1,76 @@ +package org.mozilla.vrbrowser.db; + +import android.content.Context; + +import org.mozilla.vrbrowser.AppExecutors; +import org.mozilla.vrbrowser.db.converter.DateConverter; +import org.mozilla.vrbrowser.db.dao.BookmarkDao; +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.room.Database; +import androidx.room.Room; +import androidx.room.RoomDatabase; +import androidx.room.TypeConverters; +import androidx.sqlite.db.SupportSQLiteDatabase; + +@Database(entities = {BookmarkEntity.class}, version = 1) +@TypeConverters(DateConverter.class) +public abstract class AppDatabase extends RoomDatabase { + + private static AppDatabase sInstance; + + @VisibleForTesting + public static final String DATABASE_NAME = "fxr-db"; + + public abstract BookmarkDao bookmarkDao(); + + private final MutableLiveData mIsDatabaseCreated = new MutableLiveData<>(); + + public static AppDatabase getInstance(final Context context, final AppExecutors executors) { + if (sInstance == null) { + synchronized (AppDatabase.class) { + if (sInstance == null) { + sInstance = buildDatabase(context.getApplicationContext(), executors); + sInstance.updateDatabaseCreated(context.getApplicationContext()); + } + } + } + return sInstance; + } + + private static AppDatabase buildDatabase(final Context appContext, final AppExecutors executors) { + return Room.databaseBuilder(appContext, AppDatabase.class, DATABASE_NAME) + .addCallback(new Callback() { + @Override + public void onCreate(@NonNull SupportSQLiteDatabase db) { + super.onCreate(db); + executors.diskIO().execute(() -> { + // Generate the data for pre-population + AppDatabase database = AppDatabase.getInstance(appContext, executors); + // notify that the database was created and it's ready to be used + database.setDatabaseCreated(); + }); + } + }) + .build(); + } + + private void updateDatabaseCreated(final Context context) { + if (context.getDatabasePath(DATABASE_NAME).exists()) { + setDatabaseCreated(); + } + } + + private void setDatabaseCreated(){ + mIsDatabaseCreated.postValue(true); + } + + public LiveData getDatabaseCreated() { + return mIsDatabaseCreated; + } + +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/db/converter/DateConverter.java b/app/src/common/shared/org/mozilla/vrbrowser/db/converter/DateConverter.java new file mode 100644 index 0000000000..4b91f5a533 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/db/converter/DateConverter.java @@ -0,0 +1,17 @@ +package org.mozilla.vrbrowser.db.converter; + +import java.util.Date; + +import androidx.room.TypeConverter; + +public class DateConverter { + @TypeConverter + public static Date toDate(Long timestamp) { + return timestamp == null ? null : new Date(timestamp); + } + + @TypeConverter + public static Long toTimestamp(Date date) { + return date == null ? null : date.getTime(); + } +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/db/dao/BookmarkDao.java b/app/src/common/shared/org/mozilla/vrbrowser/db/dao/BookmarkDao.java new file mode 100644 index 0000000000..a19b480054 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/db/dao/BookmarkDao.java @@ -0,0 +1,38 @@ +package org.mozilla.vrbrowser.db.dao; + +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; +import org.mozilla.vrbrowser.model.Bookmark; + +import java.util.List; + +import androidx.lifecycle.LiveData; +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; + +@Dao +public interface BookmarkDao { + + @Query("SELECT * FROM bookmarks") + LiveData> loadAllBookmarks(); + + @Query("SELECT * FROM bookmarks WHERE url LIKE :url LIMIT 1") + LiveData getBookmarkByUrlAsync(String url); + + @Insert(onConflict = OnConflictStrategy.REPLACE) + void insertBookmark(BookmarkEntity bookmark); + + @Delete + void delete(BookmarkEntity bookmark); + + @Query("DELETE FROM bookmarks WHERE id = :bookmarkId") + void deleteById(long bookmarkId); + + @Query("DELETE FROM bookmarks WHERE url LIKE :url") + void deleteByUrl(String url); + + @Query("DELETE FROM bookmarks") + void deleteAll(); +} \ No newline at end of file diff --git a/app/src/common/shared/org/mozilla/vrbrowser/db/entity/BookmarkEntity.java b/app/src/common/shared/org/mozilla/vrbrowser/db/entity/BookmarkEntity.java new file mode 100644 index 0000000000..a107a74367 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/db/entity/BookmarkEntity.java @@ -0,0 +1,87 @@ +package org.mozilla.vrbrowser.db.entity; + +import org.mozilla.vrbrowser.model.Bookmark; + +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Ignore; +import androidx.room.Index; +import androidx.room.PrimaryKey; + +@Entity(tableName = "bookmarks", + indices = {@Index(value = {"url"}, unique = true)}) +public class BookmarkEntity implements Bookmark { + + @PrimaryKey(autoGenerate = true) + private int id; + + @ColumnInfo(name = "title") + private String title; + + @ColumnInfo(name = "url") + private String url; + + @ColumnInfo(name = "timestamp") + private long timestamp; + + @Override + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + @Override + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + @Override + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public BookmarkEntity() { + } + + @Ignore + public BookmarkEntity(int id, String title, String url, long timestamp) { + this.id = id; + this.title = title; + this.url = url; + this.timestamp = timestamp; + } + + @Ignore + public BookmarkEntity(String title, String url, long timestamp) { + this.title = title; + this.url = url; + this.timestamp = timestamp; + } + + public BookmarkEntity(Bookmark bookmark) { + this.id = bookmark.getId(); + this.title = bookmark.getTitle(); + this.url = bookmark.getUrl(); + this.timestamp = bookmark.getTimestamp(); + } +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationData.java b/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationData.java index 9fc1b11af2..12e1f71b40 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationData.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationData.java @@ -1,11 +1,12 @@ package org.mozilla.vrbrowser.geolocation; -import android.support.annotation.NonNull; import android.util.Log; import org.json.JSONException; import org.json.JSONObject; +import androidx.annotation.NonNull; + /** * Class representing a Geolocation success response (HTTP 200) */ diff --git a/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationWrapper.java b/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationWrapper.java index ba5da54870..b09fe76243 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationWrapper.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/geolocation/GeolocationWrapper.java @@ -1,12 +1,13 @@ package org.mozilla.vrbrowser.geolocation; import android.content.Context; -import android.support.annotation.NonNull; import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.browser.SettingsStore; +import androidx.annotation.NonNull; + public class GeolocationWrapper { private static final int MAX_RETRIES = 2; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/model/Bookmark.java b/app/src/common/shared/org/mozilla/vrbrowser/model/Bookmark.java new file mode 100644 index 0000000000..239181fd46 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/model/Bookmark.java @@ -0,0 +1,10 @@ +package org.mozilla.vrbrowser.model; + +public interface Bookmark { + + int getId(); + String getTitle(); + String getUrl(); + long getTimestamp(); + +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java b/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java index 9902a1e566..f6ca1321e5 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/search/SearchEngineWrapper.java @@ -7,7 +7,6 @@ import android.content.SharedPreferences; import android.net.Uri; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; import org.jetbrains.annotations.Contract; import org.mozilla.vrbrowser.R; @@ -24,6 +23,7 @@ import java.util.List; import java.util.Map; +import androidx.annotation.NonNull; import kotlin.coroutines.experimental.Continuation; import mozilla.components.browser.search.SearchEngine; import mozilla.components.browser.search.SearchEngineManager; @@ -181,13 +181,7 @@ private void setupSearchEngine(@NonNull Context aContext, String userPref) { // A name can be used if the user get's to choose among the available engines mSearchEngine = mSearchEngineManager.getDefaultSearchEngine(aContext, userPref); - mSuggestionsClient = new SearchSuggestionClient(mSearchEngine, this::domainAutocompleteFilter); - } - - @NonNull - @Contract(pure = true) - private Object domainAutocompleteFilter(String aQuery, Continuation aContinuation) { - return "[\"firefox\",[\"firefox\",\"firefox for mac\",\"firefox quantum\",\"firefox update\",\"firefox esr\",\"firefox focus\",\"firefox addons\",\"firefox extensions\",\"firefox nightly\",\"firefox clear cache\"]]"; + mSuggestionsClient = new SearchSuggestionClient(mSearchEngine, (s, continuation) -> null); } private String getEngine(String aCountryCode) { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java b/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java index 52b8cac7a7..d430680c7a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/telemetry/TelemetryWrapper.java @@ -4,7 +4,6 @@ import android.content.res.Resources; import android.os.StrictMode; import android.os.SystemClock; -import android.support.annotation.UiThread; import android.util.Log; import org.mozilla.telemetry.Telemetry; @@ -26,6 +25,9 @@ import java.net.URI; import java.util.HashSet; + +import androidx.annotation.UiThread; + import static java.lang.Math.toIntExact; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/BindingAdapters.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/BindingAdapters.java new file mode 100644 index 0000000000..d4f71ef556 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/BindingAdapters.java @@ -0,0 +1,13 @@ +package org.mozilla.vrbrowser.ui; + +import android.view.View; + +import androidx.databinding.BindingAdapter; + + +public class BindingAdapters { + @BindingAdapter("visibleGone") + public static void showHide(View view, boolean show) { + view.setVisibility(show ? View.VISIBLE : View.GONE); + } +} \ No newline at end of file diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/BookmarkClickCallback.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/BookmarkClickCallback.java new file mode 100644 index 0000000000..985cba346c --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/BookmarkClickCallback.java @@ -0,0 +1,8 @@ +package org.mozilla.vrbrowser.ui; + +import org.mozilla.vrbrowser.model.Bookmark; + +public interface BookmarkClickCallback { + void onClick(Bookmark bookmark); + void onDelete(Bookmark bookmark); +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/NavigationBarCallback.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/NavigationBarCallback.java new file mode 100644 index 0000000000..68e6e8fd69 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/NavigationBarCallback.java @@ -0,0 +1,7 @@ +package org.mozilla.vrbrowser.ui; + +import org.mozilla.vrbrowser.model.Bookmark; + +public interface NavigationBarCallback { + void onBookmarkClick(Bookmark bookmark); +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BookmarkAdapter.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BookmarkAdapter.java new file mode 100644 index 0000000000..54045538b6 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/adapters/BookmarkAdapter.java @@ -0,0 +1,105 @@ +package org.mozilla.vrbrowser.ui.adapters; + +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.databinding.BookmarkItemBinding; +import org.mozilla.vrbrowser.model.Bookmark; +import org.mozilla.vrbrowser.ui.BookmarkClickCallback; + +import java.util.List; +import java.util.Objects; + +import androidx.annotation.Nullable; +import androidx.databinding.DataBindingUtil; +import androidx.recyclerview.widget.DiffUtil; +import androidx.recyclerview.widget.RecyclerView; + +public class BookmarkAdapter extends RecyclerView.Adapter { + + private List mBookmarkList; + + @Nullable + private final BookmarkClickCallback mBookmarkClickCallback; + + public BookmarkAdapter(@Nullable BookmarkClickCallback clickCallback) { + mBookmarkClickCallback = clickCallback; + setHasStableIds(true); + } + + public void setBookmarkList(final List bookmarkList) { + if (mBookmarkList == null) { + mBookmarkList = bookmarkList; + notifyItemRangeInserted(0, bookmarkList.size()); + + } else { + DiffUtil.DiffResult result = DiffUtil.calculateDiff(new DiffUtil.Callback() { + @Override + public int getOldListSize() { + return mBookmarkList.size(); + } + + @Override + public int getNewListSize() { + return bookmarkList.size(); + } + + @Override + public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { + return mBookmarkList.get(oldItemPosition).getId() == + bookmarkList.get(newItemPosition).getId(); + } + + @Override + public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { + Bookmark newBookmark = bookmarkList.get(newItemPosition); + Bookmark oldBookmark = mBookmarkList.get(oldItemPosition); + return newBookmark.getId() == oldBookmark.getId() + && Objects.equals(newBookmark.getTitle(), oldBookmark.getTitle()) + && Objects.equals(newBookmark.getUrl(), oldBookmark.getUrl()) + && newBookmark.getTimestamp() == oldBookmark.getTimestamp(); + } + }); + + mBookmarkList = bookmarkList; + result.dispatchUpdatesTo(this); + } + } + + @Override + public BookmarkViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + BookmarkItemBinding binding = DataBindingUtil + .inflate(LayoutInflater.from(parent.getContext()), R.layout.bookmark_item, + parent, false); + binding.setCallback(mBookmarkClickCallback); + return new BookmarkViewHolder(binding); + } + + @Override + public void onBindViewHolder(BookmarkViewHolder holder, int position) { + holder.binding.setBookmark(mBookmarkList.get(position)); + holder.binding.executePendingBindings(); + } + + @Override + public int getItemCount() { + return mBookmarkList == null ? 0 : mBookmarkList.size(); + } + + @Override + public long getItemId(int position) { + return mBookmarkList.get(position).getId(); + } + + static class BookmarkViewHolder extends RecyclerView.ViewHolder { + + final BookmarkItemBinding binding; + + public BookmarkViewHolder(BookmarkItemBinding binding) { + super(binding.getRoot()); + this.binding = binding; + } + } + +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/prompts/ChoicePromptWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/prompts/ChoicePromptWidget.java index c678ddd74b..3e9186e4bb 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/prompts/ChoicePromptWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/prompts/ChoicePromptWidget.java @@ -3,7 +3,6 @@ import android.content.Context; import android.graphics.Typeface; import android.os.Handler; -import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.SparseBooleanArray; import android.view.LayoutInflater; @@ -28,6 +27,8 @@ import java.util.ArrayList; import java.util.Arrays; +import androidx.annotation.NonNull; + public class ChoicePromptWidget extends UIWidget implements WidgetManagerDelegate.FocusChangeListener { private static final int DIALOG_CLOSE_DELAY = 250; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/RadioGroupSetting.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/RadioGroupSetting.java index c3a188c3e5..d5d4cbafd2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/RadioGroupSetting.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/RadioGroupSetting.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.IdRes; import android.util.AttributeSet; import android.util.TypedValue; import android.view.ContextThemeWrapper; @@ -14,6 +13,8 @@ import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.audio.AudioEngine; +import androidx.annotation.IdRes; + public class RadioGroupSetting extends LinearLayout { public interface OnCheckedChangeListener { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/SingleEditSetting.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/SingleEditSetting.java index 4b521a4a6a..3bc1b6120c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/SingleEditSetting.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/settings/SingleEditSetting.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.StringRes; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; @@ -14,6 +13,8 @@ import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.audio.AudioEngine; +import androidx.annotation.StringRes; + public class SingleEditSetting extends LinearLayout { private AudioEngine mAudio; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/CustomUIButton.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/CustomUIButton.java index ec393cbbc5..c91fa15929 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/CustomUIButton.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/CustomUIButton.java @@ -5,5 +5,5 @@ public interface CustomUIButton { void setBackground(Drawable background); - void setPrivateMode(boolean isEnabled); + void setPrivateMode(boolean isPrivate); } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/DeveloperOptionsEditText.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/DeveloperOptionsEditText.java index a2db6c971d..309220b798 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/DeveloperOptionsEditText.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/DeveloperOptionsEditText.java @@ -7,7 +7,9 @@ import android.view.View; import org.mozilla.vrbrowser.R; -public class DeveloperOptionsEditText extends android.support.v7.widget.AppCompatEditText { +import androidx.appcompat.widget.AppCompatEditText; + +public class DeveloperOptionsEditText extends AppCompatEditText { public DeveloperOptionsEditText(Context context, AttributeSet attrs) { super(context, attrs); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombButton.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombButton.java index a60c296aa5..1b99440c7c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombButton.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombButton.java @@ -5,16 +5,16 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.MotionEvent; -import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.audio.AudioEngine; +import androidx.annotation.Nullable; + public class HoneycombButton extends LinearLayout { private ImageView mIcon; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombSwitch.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombSwitch.java index c1bd3e6404..7d83f95dc2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombSwitch.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/HoneycombSwitch.java @@ -2,7 +2,6 @@ import android.content.Context; import android.content.res.TypedArray; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.widget.CompoundButton; import android.widget.LinearLayout; @@ -10,7 +9,8 @@ import android.widget.TextView; import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.audio.AudioEngine; + +import androidx.annotation.Nullable; public class HoneycombSwitch extends LinearLayout { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/MediaSeekBar.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/MediaSeekBar.java index 8154a906b1..fc1da0946f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/MediaSeekBar.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/MediaSeekBar.java @@ -2,7 +2,6 @@ import android.content.Context; import android.os.Handler; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -13,6 +12,8 @@ import org.mozilla.vrbrowser.R; +import androidx.annotation.Nullable; + public class MediaSeekBar extends LinearLayout implements SeekBar.OnSeekBarChangeListener { private SeekBar mSeekBar; private TextView mLeftText; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java index c7847dd4df..6b022f8077 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/NavigationURLBar.java @@ -14,6 +14,7 @@ import android.util.AttributeSet; import android.util.TypedValue; import android.view.GestureDetector; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.animation.Animation; @@ -25,17 +26,27 @@ import android.widget.RelativeLayout; import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.VRBrowserApplication; +import org.mozilla.vrbrowser.audio.AudioEngine; import org.mozilla.vrbrowser.browser.SessionStore; +import org.mozilla.vrbrowser.databinding.NavigationUrlBinding; +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; +import org.mozilla.vrbrowser.model.Bookmark; import org.mozilla.vrbrowser.search.SearchEngineWrapper; import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; +import org.mozilla.vrbrowser.ui.NavigationBarCallback; +import org.mozilla.vrbrowser.ui.widgets.WidgetPlacement; import org.mozilla.vrbrowser.utils.UrlUtils; +import org.mozilla.vrbrowser.viewmodel.BookmarkViewModel; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URL; import java.net.URLDecoder; -import java.util.regex.Pattern; +import androidx.annotation.StringRes; +import androidx.databinding.DataBindingUtil; +import androidx.lifecycle.Observer; import kotlin.Unit; import mozilla.components.browser.domains.DomainAutoCompleteProvider; import mozilla.components.ui.autocomplete.InlineAutocompleteEditText; @@ -55,6 +66,11 @@ public class NavigationURLBar extends FrameLayout { private int mURLWebsiteColor; private NavigationURLBarDelegate mDelegate; private DomainAutoCompleteProvider mAutocompleteProvider; + private ImageButton mBookmarkButton; + private VRBrowserApplication mApplication; + private NavigationUrlBinding mBinding; + private BookmarkViewModel mBookmarkModel; + private AudioEngine mAudio; private Unit domainAutocompleteFilter(String text, InlineAutocompleteEditText view) { if (view != null) { @@ -71,7 +87,7 @@ private Unit domainAutocompleteFilter(String text, InlineAutocompleteEditText vi public interface NavigationURLBarDelegate { void OnVoiceSearchClicked(); void OnShowSearchPopup(); - void OnHideSearchPopup(); + void onUrlBarEntered(); } public NavigationURLBar(Context context, AttributeSet attrs) { @@ -80,7 +96,13 @@ public NavigationURLBar(Context context, AttributeSet attrs) { } private void initialize(Context aContext) { - inflate(aContext, R.layout.navigation_url, this); + mApplication = (VRBrowserApplication)getContext().getApplicationContext(); + + mAudio = AudioEngine.fromContext(aContext); + + // Inflate this data binding layout + LayoutInflater inflater = LayoutInflater.from(aContext); + mBinding = DataBindingUtil.inflate(inflater, R.layout.navigation_url, this, true); // Use Domain autocomplete provider from components mAutocompleteProvider = new DomainAutoCompleteProvider(); @@ -135,6 +157,12 @@ private void initialize(Context aContext) { theme.resolveAttribute(R.attr.urlWebsiteColor, typedValue, true); mURLWebsiteColor = typedValue.data; + // Bookmarks + mBookmarkButton = findViewById(R.id.bookmarkButton); + mBookmarkButton.setSoundEffectsEnabled(false); + + setURL(""); + // Prevent the URL TextEdit to get focus when user touches something outside of it setFocusable(true); setClickable(true); @@ -144,7 +172,42 @@ public void setDelegate(NavigationURLBarDelegate delegate) { mDelegate = delegate; } + private final NavigationBarCallback mNavigationBarCallback = new NavigationBarCallback() { + @Override + public void onBookmarkClick(Bookmark bookmark) { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } + + if (bookmark == null) { + BookmarkEntity bookmarkEntity = new BookmarkEntity( + SessionStore.get().getCurrentTitle(), + SessionStore.get().getCurrentUri(), + System.currentTimeMillis()); + mApplication.getRepository().insertBookmark(bookmarkEntity); + + } else { + mApplication.getRepository().deleteBookmarkByUrl(bookmark.getUrl()); + } + } + }; + + private Observer mBookmarkObserver = bookmarkEntity -> mBookmarkModel.setBookmark(bookmarkEntity); + + public void setHint(@StringRes int aHint) { + mURL.setHint(aHint); + } + public void setURL(String aURL) { + // Setup model view for this URL + if (mBookmarkModel != null) { + mBookmarkModel.getObservableBookmark().removeObserver(mBookmarkObserver); + } + mBookmarkModel = new BookmarkViewModel(mApplication, mApplication.getRepository(), aURL); + mBinding.setBookmarkViewModel(mBookmarkModel); + mBinding.setCallback(mNavigationBarCallback); + mBookmarkModel.getObservableBookmark().observeForever(mBookmarkObserver); + mURL.removeTextChangedListener(mURLTextWatcher); int index = -1; @@ -216,14 +279,31 @@ public void setIsLoading(boolean aIsLoading) { } } + public void setBookmarks(boolean enabled) { + if (enabled) { + mMicrophoneButton.setVisibility(GONE); + mBookmarkButton.setVisibility(GONE); + + } else { + mMicrophoneButton.setVisibility(VISIBLE); + mBookmarkButton.setVisibility(VISIBLE); + } + } + public void showVoiceSearch(boolean enabled) { if (enabled) { mMicrophoneButton.setImageResource(R.drawable.ic_icon_microphone); + mMicrophoneButton.setBackgroundResource(R.drawable.url_button); + mMicrophoneButton.getLayoutParams().width = (int)getContext().getResources().getDimension(R.dimen.url_bar_item_width); mMicrophoneButton.setOnClickListener(mMicrophoneListener); + mBookmarkButton.setVisibility(VISIBLE); } else if (mURL.hasFocus()){ mMicrophoneButton.setImageResource(R.drawable.ic_icon_clear); + mMicrophoneButton.setBackgroundResource(R.drawable.url_button_end); + mMicrophoneButton.getLayoutParams().width = (int)getContext().getResources().getDimension(R.dimen.url_bar_last_item_width); mMicrophoneButton.setOnClickListener(mClearListener); + mBookmarkButton.setVisibility(GONE); } } @@ -281,7 +361,7 @@ public void handleURLEdit(String text) { SessionStore.get().loadUri(url); if (mDelegate != null) { - mDelegate.OnHideSearchPopup(); + mDelegate.onUrlBarEntered(); } } @@ -301,23 +381,25 @@ public void setClickable(boolean clickable) { mURL.setEnabled(clickable); } - private OnClickListener mMicrophoneListener = new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - if (mDelegate != null) - mDelegate.OnVoiceSearchClicked(); - - TelemetryWrapper.voiceInputEvent(); + private OnClickListener mMicrophoneListener = view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + + view.requestFocusFromTouch(); + if (mDelegate != null) + mDelegate.OnVoiceSearchClicked(); + + TelemetryWrapper.voiceInputEvent(); }; - private OnClickListener mClearListener = new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - mURL.getText().clear(); + private OnClickListener mClearListener = view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + + view.requestFocusFromTouch(); + mURL.getText().clear(); }; private TextWatcher mURLTextWatcher = new TextWatcher() { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UIButton.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UIButton.java index 451e8c2282..62579af477 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UIButton.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UIButton.java @@ -9,16 +9,22 @@ import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; -import android.support.v7.widget.AppCompatImageButton; import android.util.AttributeSet; import org.mozilla.vrbrowser.R; +import androidx.annotation.IdRes; +import androidx.appcompat.widget.AppCompatImageButton; + public class UIButton extends AppCompatImageButton implements CustomUIButton { + private ColorStateList mTintColorList; private Drawable mPrivateModeBackground; + private Drawable mActiveModeBackground; private Drawable mBackground; - private ColorStateList mPrivateModeTintColorList; + private @IdRes int mTintColorListRes; + private @IdRes int mPrivateModeTintColorListRes; + private @IdRes int mActiveModeTintColorListRes; public UIButton(Context context, AttributeSet attrs) { this(context, attrs, R.attr.imageButtonStyle); @@ -28,10 +34,9 @@ public UIButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.UIButton, defStyleAttr, 0); - mTintColorList = attributes.getColorStateList(R.styleable.UIButton_tintColorList); - if (mTintColorList != null) { - int color = mTintColorList.getColorForState(getDrawableState(), 0); - setColorFilter(color); + mTintColorListRes = attributes.getResourceId(R.styleable.UIButton_tintColorList, 0); + if (mTintColorListRes != 0) { + setTintColorList(mTintColorListRes); } attributes.recycle(); @@ -40,7 +45,15 @@ public UIButton(Context context, AttributeSet attrs, int defStyleAttr) { attributes.recycle(); attributes = context.obtainStyledAttributes(attrs, R.styleable.UIButton, defStyleAttr, 0); - mPrivateModeTintColorList = attributes.getColorStateList(R.styleable.UIButton_privateModeTintColorList); + mActiveModeBackground = attributes.getDrawable(R.styleable.UIButton_activeModeBackground); + attributes.recycle(); + + attributes = context.obtainStyledAttributes(attrs, R.styleable.UIButton, defStyleAttr, 0); + mPrivateModeTintColorListRes = attributes.getResourceId(R.styleable.UIButton_privateModeTintColorList, 0); + attributes.recycle(); + + attributes = context.obtainStyledAttributes(attrs, R.styleable.UIButton, defStyleAttr, 0); + mActiveModeTintColorListRes = attributes.getResourceId(R.styleable.UIButton_activeModeTintColorList, 0); attributes.recycle(); mBackground = getBackground(); @@ -68,24 +81,48 @@ protected void drawableStateChanged() { } @Override - public void setPrivateMode(boolean isEnabled) { - if (isEnabled) { - if (mPrivateModeBackground != null) - setBackground(mPrivateModeBackground); + public void setPrivateMode(boolean isPrivateMode) { + if (isPrivateMode) { + setPrivate(); + + } else { + setNormal(); + } + } - if (mPrivateModeTintColorList != null) { - int color = mPrivateModeTintColorList.getColorForState(getDrawableState(), 0); - setColorFilter(color); - } + public void setActiveMode(boolean isActive) { + if (isActive) { + setActive(); } else { - if (mBackground != null) - setBackground(mBackground); + setNormal(); + } + } + + private void setPrivate() { + if (mPrivateModeBackground != null) + setBackground(mPrivateModeBackground); + + if (mPrivateModeTintColorListRes != 0) { + setTintColorList(mPrivateModeTintColorListRes); + } + } + + private void setNormal() { + if (mBackground != null) + setBackground(mBackground); + + if(mTintColorListRes != 0) { + setTintColorList(mTintColorListRes); + } + } + + private void setActive() { + if (mActiveModeBackground != null) + setBackground(mActiveModeBackground); - if(mTintColorList != null) { - int color = mTintColorList.getColorForState(getDrawableState(), 0); - setColorFilter(color); - } + if (mActiveModeTintColorListRes != 0) { + setTintColorList(mActiveModeTintColorListRes); } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UITextButton.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UITextButton.java index b282498ad8..cf03ad2c3b 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UITextButton.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/UITextButton.java @@ -8,11 +8,12 @@ import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; -import android.support.v7.widget.AppCompatButton; import android.util.AttributeSet; import org.mozilla.vrbrowser.R; +import androidx.appcompat.widget.AppCompatButton; + public class UITextButton extends AppCompatButton implements CustomUIButton { private ColorStateList mTintColorList; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/VolumeControl.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/VolumeControl.java index 208c45b4b5..82e383750e 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/views/VolumeControl.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/views/VolumeControl.java @@ -1,15 +1,14 @@ package org.mozilla.vrbrowser.ui.views; import android.content.Context; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.widget.FrameLayout; -import android.widget.LinearLayout; import android.widget.SeekBar; -import android.widget.TextView; import org.mozilla.vrbrowser.R; +import androidx.annotation.Nullable; + public class VolumeControl extends FrameLayout implements SeekBar.OnSeekBarChangeListener { private SeekBar mSeekBar; private double mVolume; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BookmarkListener.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BookmarkListener.java new file mode 100644 index 0000000000..bb7b87292d --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BookmarkListener.java @@ -0,0 +1,6 @@ +package org.mozilla.vrbrowser.ui.widgets; + +public interface BookmarkListener { + void onBookmarksShow(); + void onBookmarksHide(); +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BookmarksWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BookmarksWidget.java new file mode 100644 index 0000000000..9eea2a50dc --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BookmarksWidget.java @@ -0,0 +1,291 @@ +/* -*- 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; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.LayoutInflater; + +import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.audio.AudioEngine; +import org.mozilla.vrbrowser.browser.SessionStore; +import org.mozilla.vrbrowser.browser.SettingsStore; +import org.mozilla.vrbrowser.databinding.BookmarksBinding; +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; +import org.mozilla.vrbrowser.model.Bookmark; +import org.mozilla.vrbrowser.ui.BookmarkClickCallback; +import org.mozilla.vrbrowser.ui.adapters.BookmarkAdapter; +import org.mozilla.vrbrowser.viewmodel.BookmarkListViewModel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import androidx.databinding.DataBindingUtil; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.Observer; + +import static org.mozilla.gecko.GeckoAppShell.getApplicationContext; + + +public class BookmarksWidget extends UIWidget implements Application.ActivityLifecycleCallbacks, + WidgetManagerDelegate.UpdateListener, TrayListener, NavigationBarListener { + + private BookmarksBinding mBinding; + private BookmarkAdapter mBookmarkAdapter; + private BookmarkListViewModel mBookmarkListModel; + private Widget mBrowserWidget; + private List mBookmarkListeners; + private AudioEngine mAudio; + + public BookmarksWidget(Context aContext) { + super(aContext); + initialize(aContext); + } + + public BookmarksWidget(Context aContext, AttributeSet aAttrs) { + super(aContext, aAttrs); + initialize(aContext); + } + + public BookmarksWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { + super(aContext, aAttrs, aDefStyle); + initialize(aContext); + } + + private void initialize(Context aContext) { + mBookmarkListeners = new ArrayList<>(); + + mAudio = AudioEngine.fromContext(aContext); + + ((Application)getApplicationContext()).registerActivityLifecycleCallbacks(this); + mWidgetManager.addUpdateListener(this); + + LayoutInflater inflater = LayoutInflater.from(aContext); + + // Inflate this data binding layout + mBinding = DataBindingUtil.inflate(inflater, R.layout.bookmarks, this, true); + + mBookmarkAdapter = new BookmarkAdapter(mBookmarkClickCallback); + mBinding.bookmarksList.setAdapter(mBookmarkAdapter); + + mBookmarkListModel = new BookmarkListViewModel(((Application)getApplicationContext())); + subscribeUi(mBookmarkListModel.getBookmarks()); + } + + public void addListener(BookmarkListener aListener) { + mBookmarkListeners.add(aListener); + } + + public void addListeners(BookmarkListener... listeners) { + mBookmarkListeners.addAll(Arrays.asList(listeners)); + } + + public void removeAllListeners() { + mBookmarkListeners.clear(); + } + + private void notifyBookmarksShow() { + mBookmarkListeners.forEach(bookmarkListener -> { + bookmarkListener.onBookmarksShow(); + }); + } + + private void notifyBookmarksHide() { + mBookmarkListeners.forEach(bookmarkListener -> { + bookmarkListener.onBookmarksHide(); + }); + } + + @Override + public void releaseWidget() { + ((Application)getApplicationContext()).unregisterActivityLifecycleCallbacks(this); + mWidgetManager.removeUpdateListener(this); + + super.releaseWidget(); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + + notifyBookmarksHide(); + } + + private final BookmarkClickCallback mBookmarkClickCallback = new BookmarkClickCallback() { + @Override + public void onClick(Bookmark bookmark) { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } + + SessionStore.get().loadUri(bookmark.getUrl()); + notifyBookmarksShow(); + hide(); + } + + @Override + public void onDelete(Bookmark bookmark) { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } + + mBookmarkListModel.deleteBookmark(bookmark); + } + }; + + @Override + protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { + Context context = getContext(); + aPlacement.visible = false; + aPlacement.worldWidth = WidgetPlacement.floatDimension(context, R.dimen.window_world_width); + aPlacement.width = SettingsStore.getInstance(getContext()).getWindowWidth(); + aPlacement.height = SettingsStore.getInstance(getContext()).getWindowHeight(); + aPlacement.anchorX = 0.5f; + aPlacement.anchorY = 0.0f; + aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.window_world_y); + aPlacement.translationZ = WidgetPlacement.unitFromMeters(-4.19f); + } + + private void subscribeUi(LiveData> liveData) { + // Update the list when the data changes + liveData.observeForever(mBookmarkListObserver); + } + + private void unsubscribeUi(LiveData> liveData) { + // Update the list when the data changes + liveData.removeObserver(mBookmarkListObserver); + } + + private Observer> mBookmarkListObserver = new Observer>() { + + @Override + public void onChanged(List bookmarkEntities) { + if (bookmarkEntities != null) { + if (bookmarkEntities.size() == 0) { + mBinding.setIsEmpty(true); + mBinding.setIsLoading(false); + + } else { + mBinding.setIsEmpty(false); + mBinding.setIsLoading(false); + mBookmarkAdapter.setBookmarkList(bookmarkEntities); + } + + } else { + mBinding.setIsLoading(true); + } + // espresso does not know how to wait for data binding's loop so we execute changes + // sync. + mBinding.executePendingBindings(); + } + }; + + public void setBrowserWidget(Widget widget) { + mBrowserWidget = widget; + } + + public void show() { + super.show(); + + notifyBookmarksShow(); + } + + public void hide() { + super.hide(); + + notifyBookmarksHide(); + } + + // ActivityLifecycleCallbacks + + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityStarted(Activity activity) { + subscribeUi(mBookmarkListModel.getBookmarks()); + } + + @Override + public void onActivityResumed(Activity activity) { + + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + unsubscribeUi(mBookmarkListModel.getBookmarks()); + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + + } + + // UpdateListener + + @Override + public void onWidgetUpdate(Widget aWidget) { + if (aWidget != mBrowserWidget) { + return; + } + + mWidgetPlacement.worldWidth = aWidget.getPlacement().worldWidth; + mWidgetPlacement.width = aWidget.getPlacement().width; + mWidgetPlacement.height = aWidget.getPlacement().height; + mWidgetManager.updateWidget(this); + } + + // TrayListener + + @Override + public void onBookmarksClicked() { + toggle(); + } + + @Override + public void onHelpClicked() { + if (mWidgetPlacement.visible) { + hide(); + } + } + + @Override + public void onSettingsClicked() { + + } + + @Override + public void onPrivateBrowsingClicked() { + if (mWidgetPlacement.visible) { + hide(); + } + } + + // NavigationBarListener + + @Override + public void onNavigationStarted() { + if (mWidgetPlacement.visible) { + hide(); + } + } +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BrowserWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BrowserWidget.java index bdb2de66e3..ecdc572c29 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BrowserWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/BrowserWidget.java @@ -5,7 +5,9 @@ package org.mozilla.vrbrowser.ui.widgets; +import android.annotation.SuppressLint; import android.content.Context; +import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.util.Log; @@ -15,6 +17,8 @@ import android.view.View; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; +import android.widget.FrameLayout; +import android.widget.LinearLayout; import org.mozilla.geckoview.AllowOrDeny; import org.mozilla.geckoview.GeckoDisplay; @@ -24,17 +28,18 @@ import org.mozilla.vrbrowser.*; import org.mozilla.vrbrowser.browser.SessionStore; import org.mozilla.vrbrowser.browser.SettingsStore; +import org.mozilla.vrbrowser.model.Bookmark; import org.mozilla.vrbrowser.ui.prompts.ChoicePromptWidget; -public class BrowserWidget extends View implements Widget, SessionStore.SessionChangeListener, GeckoSession.PromptDelegate { +public class BrowserWidget extends UIWidget implements SessionStore.SessionChangeListener, + GeckoSession.PromptDelegate, BookmarkListener { private static final String LOGTAG = "VRB"; private int mSessionId; private GeckoDisplay mDisplay; private Surface mSurface; - private SurfaceTexture mSurfaceTexture; private int mWidth; private int mHeight; private int mHandle; @@ -63,18 +68,43 @@ public BrowserWidget(Context aContext, int aSessionId) { SettingsStore.getInstance(getContext()).getBrowserWorldHeight()); } - private void initializeWidgetPlacement(WidgetPlacement aPlacement) { + @Override + protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { Context context = getContext(); + aPlacement.worldWidth = WidgetPlacement.floatDimension(context, R.dimen.window_world_width); aPlacement.width = SettingsStore.getInstance(getContext()).getWindowWidth(); aPlacement.height = SettingsStore.getInstance(getContext()).getWindowHeight(); aPlacement.density = 1.0f; aPlacement.translationX = 0.0f; - aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.browser_world_y); - aPlacement.translationZ = WidgetPlacement.unitFromMeters(context, R.dimen.browser_world_z); + aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.window_world_y); + aPlacement.translationZ = WidgetPlacement.unitFromMeters(context, R.dimen.window_world_z); aPlacement.anchorX = 0.5f; aPlacement.anchorY = 0.0f; } + @Override + public void show(boolean focus) { + if (!mWidgetPlacement.visible) { + mWidgetPlacement.visible = true; + mWidgetManager.pushBackHandler(mBackHandler); + } + + if (focus) { + setFocusableInTouchMode(true); + requestFocusFromTouch(); + } + } + + @Override + public void hide() { + if (mWidgetPlacement.visible) { + mWidgetPlacement.visible = false; + mWidgetManager.popBackHandler(mBackHandler); + } + + clearFocus(); + } + public void pauseCompositor() { if (mDisplay == null) { return; @@ -118,8 +148,9 @@ public void disableVRVideoMode() { resizeSurfaceTexture(mWidthBackup, mWidthBackup); } - public void setBrowserSize(float windowWidth, float windowHeight, float multiplier) { - float worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width); + @Override + public void setSize(float windowWidth, float windowHeight, float multiplier) { + float worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width); float aspect = windowWidth / windowHeight; float worldHeight = worldWidth / aspect; float area = worldWidth * worldHeight * multiplier; @@ -136,9 +167,13 @@ public void setSurfaceTexture(SurfaceTexture aTexture, final int aWidth, final i if (session == null) { return; } + if (aTexture == null) { + setWillNotDraw(true); + return; + } mWidth = aWidth; mHeight = aHeight; - mSurfaceTexture = aTexture; + mTexture = aTexture; aTexture.setDefaultBufferSize(aWidth, aHeight); mSurface = new Surface(aTexture); if (mDisplay == null) { @@ -153,7 +188,7 @@ public void setSurfaceTexture(SurfaceTexture aTexture, final int aWidth, final i public void resizeSurfaceTexture(final int aWidth, final int aHeight) { mWidth = aWidth; mHeight = aHeight; - mSurfaceTexture.setDefaultBufferSize(aWidth, aHeight); + mTexture.setDefaultBufferSize(aWidth, aHeight); mDisplay.surfaceChanged(mSurface, aWidth, aHeight); } @@ -191,7 +226,7 @@ public void handleHoverEvent(MotionEvent aEvent) { @Override public void handleResizeEvent(float aWorldWidth, float aWorldHeight) { - float worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width); + float worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width); int defaultWidth = SettingsStore.getInstance(getContext()).getWindowWidth(); int defaultHeight = SettingsStore.getInstance(getContext()).getWindowHeight(); @@ -250,6 +285,13 @@ public void setVisible(boolean aVisible) { } } + @SuppressLint("MissingSuperCall") + @Override + public void draw(Canvas aCanvas) { + // Nothing to do + + } + // SessionStore.GeckoSessionChange @Override public void onNewSession(GeckoSession aSession, int aId) { @@ -406,12 +448,9 @@ public void onChoicePrompt(GeckoSession session, String title, String msg, int t mChoicePrompt.setMessage(msg); mChoicePrompt.setChoices(choices); mChoicePrompt.setMenuType(type); - mChoicePrompt.setDelegate(new ChoicePromptWidget.ChoicePromptDelegate() { - @Override - public void onDismissed(String[] ids) { - callback.confirm(ids); - mChoicePrompt.hide(); - } + mChoicePrompt.setDelegate(ids -> { + callback.confirm(ids); + mChoicePrompt.hide(); }); mChoicePrompt.show(); @@ -436,4 +475,20 @@ public void onFilePrompt(GeckoSession session, String title, int type, String[] public GeckoResult onPopupRequest(final GeckoSession session, final String targetUri) { return GeckoResult.fromValue(AllowOrDeny.ALLOW); } + + // BookmarkListener + + @Override + public void onBookmarksShow() { + pauseCompositor(); + SessionStore.get().setActive(false); + hide(); + } + + @Override + public void onBookmarksHide() { + resumeCompositor(); + SessionStore.get().setActive(true); + show(); + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java index 73a564a642..0a7260af01 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/KeyboardWidget.java @@ -9,7 +9,6 @@ import android.graphics.drawable.Drawable; import android.inputmethodservice.Keyboard; import android.os.Handler; -import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; @@ -26,11 +25,13 @@ import org.mozilla.geckoview.GeckoSession; import org.mozilla.vrbrowser.R; import org.mozilla.vrbrowser.browser.SessionStore; -import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; import org.mozilla.vrbrowser.input.CustomKeyboard; +import org.mozilla.vrbrowser.telemetry.TelemetryWrapper; import org.mozilla.vrbrowser.ui.views.CustomKeyboardView; import org.mozilla.vrbrowser.ui.views.UIButton; +import androidx.annotation.NonNull; + public class KeyboardWidget extends UIWidget implements CustomKeyboardView.OnKeyboardActionListener, GeckoSession.TextInputDelegate, WidgetManagerDelegate.FocusChangeListener { @@ -49,7 +50,7 @@ public class KeyboardWidget extends UIWidget implements CustomKeyboardView.OnKey private Drawable mShiftOffIcon; private Drawable mCapsLockOnIcon; private View mFocusedView; - private BrowserWidget mBrowserWidget; + private UIWidget mBrowserWidget; private InputConnection mInputConnection; private EditorInfo mEditorInfo = new EditorInfo(); @@ -192,7 +193,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.visible = false; } - public void setBrowserWidget(BrowserWidget aWidget) { + public void setBrowserWidget(UIWidget aWidget) { mBrowserWidget = aWidget; if (mBrowserWidget != null) { mWidgetPlacement.parentHandle = mBrowserWidget.getHandle(); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarListener.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarListener.java new file mode 100644 index 0000000000..a4433a590c --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/NavigationBarListener.java @@ -0,0 +1,5 @@ +package org.mozilla.vrbrowser.ui.widgets; + +public interface NavigationBarListener { + void onNavigationStarted(); +} 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 0c8ddc600f..9025aed684 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 @@ -9,8 +9,6 @@ import android.content.SharedPreferences; import android.net.Uri; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.util.AttributeSet; import android.util.Log; import android.view.View; @@ -36,12 +34,17 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class NavigationBarWidget extends UIWidget implements GeckoSession.NavigationDelegate, GeckoSession.ProgressDelegate, GeckoSession.ContentDelegate, WidgetManagerDelegate.WorldClickListener, WidgetManagerDelegate.UpdateListener, SessionStore.SessionChangeListener, NavigationURLBar.NavigationURLBarDelegate, VoiceSearchWidget.VoiceSearchDelegate, - SharedPreferences.OnSharedPreferenceChangeListener, SuggestionsWidget.URLBarPopupDelegate { + SharedPreferences.OnSharedPreferenceChangeListener, SuggestionsWidget.URLBarPopupDelegate, + BookmarkListener { private static final String LOGTAG = "VRB"; @@ -83,6 +86,7 @@ public class NavigationBarWidget extends UIWidget implements GeckoSession.Naviga private WidgetPlacement mProjectionMenuPlacement; private BrightnessMenuWidget mBrigthnessWidget; private MediaControlsWidget mMediaControlsWidget; + private List mNavigationBarListeners; public NavigationBarWidget(Context aContext) { super(aContext); @@ -102,6 +106,9 @@ public NavigationBarWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) private void initialize(Context aContext) { mAppContext = aContext.getApplicationContext(); inflate(aContext, R.layout.navigation_bar, this); + + mNavigationBarListeners = new ArrayList<>(); + mAudio = AudioEngine.fromContext(aContext); mBackButton = findViewById(R.id.backButton); mForwardButton = findViewById(R.id.forwardButton); @@ -123,66 +130,55 @@ private void initialize(Context aContext) { mFullScreenBackHandler = this::exitFullScreenMode; mVRVideoBackHandler = this::exitVRVideo; - mBackButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - v.requestFocusFromTouch(); - if (SessionStore.get().canGoBack()) - SessionStore.get().goBack(); - else if (SessionStore.get().canUnstackSession()) - SessionStore.get().unstackSession(); - - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.BACK); - } + mBackButton.setOnClickListener(v -> { + v.requestFocusFromTouch(); + if (SessionStore.get().canGoBack()) + SessionStore.get().goBack(); + else if (SessionStore.get().canUnstackSession()) + SessionStore.get().unstackSession(); + + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.BACK); } + notifyNavigationStarted(); }); - mForwardButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - v.requestFocusFromTouch(); - SessionStore.get().goForward(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mForwardButton.setOnClickListener(v -> { + v.requestFocusFromTouch(); + SessionStore.get().goForward(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + notifyNavigationStarted(); }); - mReloadButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - v.requestFocusFromTouch(); - if (mIsLoading) { - SessionStore.get().stop(); - } else { - SessionStore.get().reload(); - } - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mReloadButton.setOnClickListener(v -> { + v.requestFocusFromTouch(); + if (mIsLoading) { + SessionStore.get().stop(); + } else { + SessionStore.get().reload(); + } + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + notifyNavigationStarted(); }); - mHomeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - v.requestFocusFromTouch(); - SessionStore.get().loadUri(SessionStore.get().getHomeUri()); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mHomeButton.setOnClickListener(v -> { + v.requestFocusFromTouch(); + SessionStore.get().loadUri(SessionStore.get().getHomeUri()); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + notifyNavigationStarted(); }); - mServoButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - v.requestFocusFromTouch(); - SessionStore.get().toggleServo(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mServoButton.setOnClickListener(v -> { + v.requestFocusFromTouch(); + SessionStore.get().toggleServo(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); @@ -193,125 +189,95 @@ public void onClick(View v) { mPreset2 = findViewById(R.id.resizePreset2); mPreset3 = findViewById(R.id.resizePreset3); - mResizeEnterButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - enterResizeMode(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mResizeEnterButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + enterResizeMode(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mResizeExitButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - exitResizeMode(true); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mResizeExitButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + exitResizeMode(true); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mFullScreenResizeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - enterResizeMode(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mFullScreenResizeButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + enterResizeMode(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mFullScreenExitButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - exitFullScreenMode(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mFullScreenExitButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + exitFullScreenMode(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mProjectionButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mProjectionButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } - boolean wasVisible = mProjectionMenu.isVisible(); - closeFloatingMenus(); - if (!wasVisible) { - mProjectionMenu.setVisible(true); - } + boolean wasVisible = mProjectionMenu.isVisible(); + closeFloatingMenus(); + if (!wasVisible) { + mProjectionMenu.setVisible(true); } }); - mBrightnessButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } - boolean wasVisible = mBrigthnessWidget.isVisible(); - closeFloatingMenus(); - if (!wasVisible) { - float anchor = 0.5f + (float)mBrightnessButton.getMeasuredWidth() / (float)NavigationBarWidget.this.getMeasuredWidth(); - mBrigthnessWidget.getPlacement().parentAnchorX = anchor; - mBrigthnessWidget.setVisible(true); - } + mBrightnessButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } + boolean wasVisible = mBrigthnessWidget.isVisible(); + closeFloatingMenus(); + if (!wasVisible) { + float anchor = 0.5f + (float)mBrightnessButton.getMeasuredWidth() / (float)NavigationBarWidget.this.getMeasuredWidth(); + mBrigthnessWidget.getPlacement().parentAnchorX = anchor; + mBrigthnessWidget.setVisible(true); } }); - mPreset0.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - setResizePreset(0.5f); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mPreset0.setOnClickListener(view -> { + view.requestFocusFromTouch(); + setResizePreset(0.5f); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mPreset1.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - setResizePreset(1.0f); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mPreset1.setOnClickListener(view -> { + view.requestFocusFromTouch(); + setResizePreset(1.0f); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mPreset2.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - setResizePreset(2.0f); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mPreset2.setOnClickListener(view -> { + view.requestFocusFromTouch(); + setResizePreset(2.0f); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); - mPreset3.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - setResizePreset(3.0f); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mPreset3.setOnClickListener(view -> { + view.requestFocusFromTouch(); + setResizePreset(3.0f); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } }); @@ -343,6 +309,22 @@ public void onClick(View view) { updateServoButton(); } + public void addListener(NavigationBarListener aListener) { + mNavigationBarListeners.add(aListener); + } + + public void addListeners(NavigationBarListener... listeners) { + mNavigationBarListeners.addAll(Arrays.asList(listeners)); + } + + public void removeAllListeners() { + mNavigationBarListeners.clear(); + } + + private void notifyNavigationStarted() { + mNavigationBarListeners.forEach(navigationBarListener -> navigationBarListener.onNavigationStarted()); + } + @Override public void releaseWidget() { mWidgetManager.removeUpdateListener(this); @@ -359,7 +341,7 @@ public void releaseWidget() { @Override protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.width = WidgetPlacement.dpDimension(getContext(), R.dimen.navigation_bar_width); - aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width); + aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width); aPlacement.height = WidgetPlacement.dpDimension(getContext(), R.dimen.navigation_bar_height); aPlacement.anchorX = 0.5f; aPlacement.anchorY = 1.0f; @@ -525,7 +507,7 @@ private void exitVRVideo() { } private void setResizePreset(float aResizeMode) { - mBrowserWidget.setBrowserSize( + mBrowserWidget.setSize( SettingsStore.getInstance(getContext()).getWindowWidth(), SettingsStore.getInstance(getContext()).getWindowHeight(), aResizeMode); @@ -599,7 +581,8 @@ public void onCanGoForward(GeckoSession aSession, boolean canGoForward) { } @Override - public @Nullable GeckoResult onLoadRequest(GeckoSession aSession, @NonNull LoadRequest aRequest) { + public @Nullable + GeckoResult onLoadRequest(GeckoSession aSession, @NonNull LoadRequest aRequest) { if (mURLBar != null) { Log.d(LOGTAG, "Got onLoadUri"); mURLBar.setURL(aRequest.uri); @@ -732,7 +715,7 @@ public void onWidgetUpdate(Widget aWidget) { // Browser window may have been resized, adjust the navigation bar float targetWidth = aWidget.getPlacement().worldWidth; - float defaultWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width); + float defaultWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width); targetWidth = Math.max(defaultWidth, targetWidth); targetWidth = Math.min(targetWidth, defaultWidth * 1.5f); @@ -832,7 +815,9 @@ public void OnShowSearchPopup() { } @Override - public void OnHideSearchPopup() { + public void onUrlBarEntered() { + notifyNavigationStarted(); + if (mPopup != null && mPopup.isVisible()) { mPopup.hide(); } @@ -903,4 +888,22 @@ public void OnItemClicked(SuggestionsWidget.SuggestionItem item) { public void OnItemDeleted(SuggestionsWidget.SuggestionItem item) { } + + // BookmarkListener + + @Override + public void onBookmarksShow() { + mResizeEnterButton.setEnabled(false); + mURLBar.setBookmarks(true); + mURLBar.setURL(""); + mURLBar.setHint(R.string.about_bookmarks); + } + + @Override + public void onBookmarksHide() { + mResizeEnterButton.setEnabled(true); + mURLBar.setBookmarks(false); + mURLBar.setURL(SessionStore.get().getCurrentUri()); + mURLBar.setHint(R.string.search_placeholder); + } } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java index f214814bca..29a2fdf735 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/SuggestionsWidget.java @@ -2,7 +2,6 @@ import android.content.Context; import android.graphics.Typeface; -import android.support.annotation.NonNull; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.style.StyleSpan; @@ -26,6 +25,8 @@ import java.util.ArrayList; import java.util.List; +import androidx.annotation.NonNull; + public class SuggestionsWidget extends UIWidget implements WidgetManagerDelegate.FocusChangeListener { private ListView mList; @@ -153,7 +154,7 @@ public void setItems(List items) { } public void updatePlacement() { - float worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width); + float worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width); float aspect = mWidgetPlacement.width / mWidgetPlacement.height; float worldHeight = worldWidth / aspect; float area = worldWidth * worldHeight; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java index 018ebbb7a6..32f44a5ea8 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TopBarWidget.java @@ -7,21 +7,19 @@ import android.content.Context; import android.util.AttributeSet; -import android.view.View; import org.mozilla.geckoview.GeckoSession; import org.mozilla.geckoview.GeckoSessionSettings; import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.browser.SessionStore; import org.mozilla.vrbrowser.audio.AudioEngine; +import org.mozilla.vrbrowser.browser.SessionStore; import org.mozilla.vrbrowser.ui.views.UIButton; public class TopBarWidget extends UIWidget implements SessionStore.SessionChangeListener, WidgetManagerDelegate.UpdateListener { - private static final String LOGTAG = "VRB"; private UIButton mCloseButton; private AudioEngine mAudio; - private BrowserWidget mBrowserWidget; + private UIWidget mBrowserWidget; public TopBarWidget(Context aContext) { super(aContext); @@ -42,16 +40,13 @@ private void initialize(Context aContext) { inflate(aContext, R.layout.top_bar, this); mCloseButton = findViewById(R.id.closeButton); - mCloseButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - view.requestFocusFromTouch(); - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } - - SessionStore.get().exitPrivateMode(); + mCloseButton.setOnClickListener(view -> { + view.requestFocusFromTouch(); + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + + SessionStore.get().exitPrivateMode(); }); mAudio = AudioEngine.fromContext(aContext); @@ -66,7 +61,7 @@ protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { aPlacement.width = WidgetPlacement.dpDimension(context, R.dimen.top_bar_width); aPlacement.height = WidgetPlacement.dpDimension(context, R.dimen.top_bar_height); // FIXME: Something wrong with the DPI ratio? Revert to top_bar_world_width when fixed - aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width) * aPlacement.width/getWorldWidth(); + aPlacement.worldWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width) * aPlacement.width/getWorldWidth(); aPlacement.translationY = WidgetPlacement.unitFromMeters(context, R.dimen.top_bar_world_y); aPlacement.anchorX = 0.5f; aPlacement.anchorY = 0.5f; @@ -83,7 +78,7 @@ public void releaseWidget() { super.releaseWidget(); } - public void setBrowserWidget(BrowserWidget aWidget) { + public void setBrowserWidget(UIWidget aWidget) { if (aWidget != null) { mWidgetPlacement.parentHandle = aWidget.getHandle(); } @@ -128,7 +123,7 @@ public void onWidgetUpdate(Widget aWidget) { // Browser window may have been resized, adjust the navigation bar float targetWidth = aWidget.getPlacement().worldWidth; // FIXME: Something wrong with the DPI ratio? Revert to top_bar_world_width when fixed - float defaultWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.browser_world_width) * 40/720; + float defaultWidth = WidgetPlacement.floatDimension(getContext(), R.dimen.window_world_width) * 40/720; targetWidth = Math.max(defaultWidth, targetWidth); float ratio = targetWidth / defaultWidth; diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayListener.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayListener.java new file mode 100644 index 0000000000..26f54eb84c --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayListener.java @@ -0,0 +1,8 @@ +package org.mozilla.vrbrowser.ui.widgets; + +public interface TrayListener { + void onBookmarksClicked(); + void onHelpClicked(); + void onSettingsClicked(); + void onPrivateBrowsingClicked(); +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java index 0bdf4aee80..1a47984a6c 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/TrayWidget.java @@ -7,25 +7,28 @@ import android.content.Context; import android.util.AttributeSet; -import android.view.View; import org.mozilla.geckoview.GeckoSession; import org.mozilla.geckoview.GeckoSessionSettings; import org.mozilla.vrbrowser.R; -import org.mozilla.vrbrowser.browser.SessionStore; import org.mozilla.vrbrowser.audio.AudioEngine; +import org.mozilla.vrbrowser.browser.SessionStore; import org.mozilla.vrbrowser.ui.views.UIButton; -public class TrayWidget extends UIWidget implements SessionStore.SessionChangeListener { +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; - private static final String LOGTAG = "VRB"; +public class TrayWidget extends UIWidget implements SessionStore.SessionChangeListener, BookmarkListener { private UIButton mHelpButton; private UIButton mSettingsButton; private UIButton mPrivateButton; + private UIButton mBookmarksButton; private AudioEngine mAudio; private int mSettingsDialogHandle = -1; private boolean mIsLastSessionPrivate; + private List mTrayListeners; public TrayWidget(Context aContext) { super(aContext); @@ -45,47 +48,50 @@ public TrayWidget(Context aContext, AttributeSet aAttrs, int aDefStyle) { private void initialize(Context aContext) { inflate(aContext, R.layout.tray, this); - mHelpButton = findViewById(R.id.helpButton); - mHelpButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } - - onHelpButtonClicked(); + mTrayListeners = new ArrayList<>(); - view.requestFocusFromTouch(); + mHelpButton = findViewById(R.id.helpButton); + mHelpButton.setOnClickListener(view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + + onHelpButtonClicked(); + view.requestFocusFromTouch(); + notifyHelpClicked(); }); mPrivateButton = findViewById(R.id.privateButton); - mPrivateButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } - - SessionStore.get().switchPrivateMode(); - - view.requestFocusFromTouch(); + mPrivateButton.setOnClickListener(view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + + SessionStore.get().switchPrivateMode(); + view.requestFocusFromTouch(); + notifyProvateBrowsingClicked(); }); mSettingsButton = findViewById(R.id.settingsButton); - mSettingsButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - if (mAudio != null) { - mAudio.playSound(AudioEngine.Sound.CLICK); - } + mSettingsButton.setOnClickListener(view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); + } - toggleSettingsDialog(); + toggleSettingsDialog(); + if (isDialogOpened(mSettingsDialogHandle)) + view.requestFocusFromTouch(); + notifySettingsClicked(); + }); - if (isSettingsDialogOpened()) - view.requestFocusFromTouch(); + mBookmarksButton = findViewById(R.id.bookmarksButton); + mBookmarksButton.setOnClickListener(view -> { + if (mAudio != null) { + mAudio.playSound(AudioEngine.Sound.CLICK); } + + view.requestFocusFromTouch(); + notifyBookmarksClicked(); }); mAudio = AudioEngine.fromContext(aContext); @@ -95,6 +101,42 @@ public void onClick(View view) { SessionStore.get().addSessionChangeListener(this); } + public void addListener(TrayListener aListener) { + mTrayListeners.add(aListener); + } + + public void addListeners(TrayListener... listeners) { + mTrayListeners.addAll(Arrays.asList(listeners)); + } + + public void removeAllListeners() { + mTrayListeners.clear(); + } + + private void notifyBookmarksClicked() { + mTrayListeners.forEach(trayListener -> { + trayListener.onBookmarksClicked(); + }); + } + + private void notifyHelpClicked() { + mTrayListeners.forEach(trayListener -> { + trayListener.onHelpClicked(); + }); + } + + private void notifySettingsClicked() { + mTrayListeners.forEach(trayListener -> { + trayListener.onSettingsClicked(); + }); + } + + private void notifyProvateBrowsingClicked() { + mTrayListeners.forEach(trayListener -> { + trayListener.onPrivateBrowsingClicked(); + }); + } + @Override protected void initializeWidgetPlacement(WidgetPlacement aPlacement) { Context context = getContext(); @@ -180,9 +222,8 @@ public void hide() { } } - - public boolean isSettingsDialogOpened() { - UIWidget widget = getChild(mSettingsDialogHandle); + public boolean isDialogOpened(int aHandle) { + UIWidget widget = getChild(aHandle); if (widget != null) { return widget.isVisible(); } @@ -199,4 +240,16 @@ private void onHelpButtonClicked() { SessionStore.get().loadUri(getContext().getString(R.string.help_url)); } + // BookmarkListener + + @Override + public void onBookmarksShow() { + mBookmarksButton.setActiveMode(true); + } + + @Override + public void onBookmarksHide() { + mBookmarksButton.setActiveMode(false); + } + } diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java index 4a9ff8894a..6456ed3492 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UISurfaceTextureRenderer.java @@ -10,8 +10,6 @@ import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.SurfaceTexture; -import android.opengl.GLES11Ext; -import android.opengl.GLES20; import android.view.Surface; class UISurfaceTextureRenderer { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java index 69d8cb2cc6..a47512990f 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/UIWidget.java @@ -9,7 +9,6 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.SurfaceTexture; -import android.support.annotation.NonNull; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -22,6 +21,8 @@ import java.lang.reflect.Constructor; import java.util.HashMap; +import androidx.annotation.NonNull; + public abstract class UIWidget extends FrameLayout implements Widget { private static final String LOGTAG = "VRB"; @@ -30,9 +31,9 @@ public interface Delegate { void onDismiss(); } - private UISurfaceTextureRenderer mRenderer; - private SurfaceTexture mTexture; - private float mWorldWidth; + protected UISurfaceTextureRenderer mRenderer; + protected SurfaceTexture mTexture; + protected float mWorldWidth; protected int mHandle; protected WidgetPlacement mWidgetPlacement; protected WidgetManagerDelegate mWidgetManager; @@ -67,14 +68,13 @@ private void initialize() { mWorldWidth = WidgetPlacement.pixelDimension(getContext(), R.dimen.world_width); mChildren = new HashMap<>(); - mBackHandler = new Runnable() { - @Override - public void run() { - onDismiss(); - } - }; + mBackHandler = () -> onDismiss(); } + @Override + public void setSize(float windowWidth, float windowHeight, float multiplier) { + // To be implemented by inheriting widgets + } protected abstract void initializeWidgetPlacement(WidgetPlacement aPlacement); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VideoProjectionMenuWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VideoProjectionMenuWidget.java index 29f29e60f3..56e6fca675 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VideoProjectionMenuWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VideoProjectionMenuWidget.java @@ -1,13 +1,14 @@ package org.mozilla.vrbrowser.ui.widgets; import android.content.Context; -import android.support.annotation.IntDef; -import android.support.annotation.Nullable; import org.mozilla.vrbrowser.R; import java.util.ArrayList; +import androidx.annotation.IntDef; +import androidx.annotation.Nullable; + public class VideoProjectionMenuWidget extends MenuWidget { @IntDef(value = { VIDEO_PROJECTION_3D_SIDE_BY_SIDE, VIDEO_PROJECTION_360, diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VoiceSearchWidget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VoiceSearchWidget.java index 5778086e19..da4d3a733a 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VoiceSearchWidget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/VoiceSearchWidget.java @@ -9,8 +9,6 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.os.Bundle; -import android.support.annotation.IdRes; -import android.support.v4.app.ActivityCompat; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; @@ -29,6 +27,9 @@ import org.mozilla.vrbrowser.audio.AudioEngine; import org.mozilla.vrbrowser.ui.views.UIButton; +import androidx.annotation.IdRes; +import androidx.core.app.ActivityCompat; + import static org.mozilla.gecko.GeckoAppShell.getApplicationContext; public class VoiceSearchWidget extends UIWidget implements WidgetManagerDelegate.PermissionListener, diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java index 858c31cdd3..e1556285f5 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/widgets/Widget.java @@ -21,4 +21,5 @@ public interface Widget { boolean getFirstDraw(); boolean isVisible(); void setVisible(boolean aVisible); + void setSize(float windowWidth, float windowHeight, float multiplier); } 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 adea291471..26665a498d 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 @@ -1,10 +1,11 @@ package org.mozilla.vrbrowser.ui.widgets; -import android.support.annotation.NonNull; import android.view.View; import org.mozilla.geckoview.GeckoSession; +import androidx.annotation.NonNull; + public interface WidgetManagerDelegate { interface UpdateListener { void onWidgetUpdate(Widget aWidget); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java index 9e8eca9a25..c84df11aa2 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/utils/UrlUtils.java @@ -5,10 +5,10 @@ package org.mozilla.vrbrowser.utils; -import android.support.annotation.Nullable; - import java.util.regex.Pattern; +import androidx.annotation.Nullable; + // This class refers from mozilla-mobile/focus-android public class UrlUtils { diff --git a/app/src/common/shared/org/mozilla/vrbrowser/utils/ValueHolder.java b/app/src/common/shared/org/mozilla/vrbrowser/utils/ValueHolder.java deleted file mode 100644 index 2c12f7af2a..0000000000 --- a/app/src/common/shared/org/mozilla/vrbrowser/utils/ValueHolder.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.mozilla.vrbrowser.utils; - -public class ValueHolder { - - private T value; - - public ValueHolder(T aValue) { - value = aValue; - } - - public T getValue() { - return value; - } - - public void setValue(Object newValue) { - value = (T) newValue; - } - -} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/viewmodel/BookmarkListViewModel.java b/app/src/common/shared/org/mozilla/vrbrowser/viewmodel/BookmarkListViewModel.java new file mode 100644 index 0000000000..e8fdfa5b65 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/viewmodel/BookmarkListViewModel.java @@ -0,0 +1,41 @@ +package org.mozilla.vrbrowser.viewmodel; + +import android.app.Application; + +import org.mozilla.vrbrowser.DataRepository; +import org.mozilla.vrbrowser.VRBrowserApplication; +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; +import org.mozilla.vrbrowser.model.Bookmark; + +import java.util.List; + +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MediatorLiveData; + +public class BookmarkListViewModel extends AndroidViewModel { + + private final DataRepository mRepository; + + private final MediatorLiveData> mObservableBookmarks; + + public BookmarkListViewModel(Application application) { + super(application); + + mObservableBookmarks = new MediatorLiveData<>(); + mObservableBookmarks.setValue(null); + + mRepository = ((VRBrowserApplication) application).getRepository(); + LiveData> bookmarks = mRepository.getBookmarks(); + + mObservableBookmarks.addSource(bookmarks, mObservableBookmarks::setValue); + } + + public LiveData> getBookmarks() { + return mObservableBookmarks; + } + + public void deleteBookmark(Bookmark bookmark) { + mRepository.deleteBookmark(bookmark); + } +} diff --git a/app/src/common/shared/org/mozilla/vrbrowser/viewmodel/BookmarkViewModel.java b/app/src/common/shared/org/mozilla/vrbrowser/viewmodel/BookmarkViewModel.java new file mode 100644 index 0000000000..84f6b55e45 --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/viewmodel/BookmarkViewModel.java @@ -0,0 +1,36 @@ +package org.mozilla.vrbrowser.viewmodel; + +import android.app.Application; + +import org.mozilla.vrbrowser.DataRepository; +import org.mozilla.vrbrowser.db.entity.BookmarkEntity; + +import androidx.annotation.NonNull; +import androidx.databinding.ObservableField; +import androidx.lifecycle.AndroidViewModel; +import androidx.lifecycle.LiveData; + +public class BookmarkViewModel extends AndroidViewModel { + + private final LiveData mObservableBookmark; + + public ObservableField bookmark = new ObservableField<>(); + + private final String mBookmarkUrl; + + public BookmarkViewModel(@NonNull Application application, DataRepository repository, + final String bookmarkUrl) { + super(application); + mBookmarkUrl = bookmarkUrl; + + mObservableBookmark = repository.getBookmarkByUrl(mBookmarkUrl); + } + + public LiveData getObservableBookmark() { + return mObservableBookmark; + } + + public void setBookmark(BookmarkEntity bookmark) { + this.bookmark.set(bookmark); + } +} diff --git a/app/src/googlevrFlat/AndroidManifest.xml b/app/src/googlevrFlat/AndroidManifest.xml deleted file mode 100644 index f38b84cdf4..0000000000 --- a/app/src/googlevrFlat/AndroidManifest.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/googlevrFlat/java/org/mozilla/vrbrowser/BrowserActivity.java b/app/src/googlevrFlat/java/org/mozilla/vrbrowser/BrowserActivity.java deleted file mode 100644 index 734c848b45..0000000000 --- a/app/src/googlevrFlat/java/org/mozilla/vrbrowser/BrowserActivity.java +++ /dev/null @@ -1,371 +0,0 @@ -package org.mozilla.vrbrowser; - -import android.app.Activity; - -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Color; -import android.media.Image; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.inputmethod.EditorInfo; -import android.widget.EditText; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.TextView; - -import org.mozilla.geckoview.GeckoSession; -import org.mozilla.geckoview.GeckoSessionSettings; -import org.mozilla.geckoview.GeckoView; -import org.mozilla.gecko.util.GeckoBundle; -import org.mozilla.vrbrowser.SessionStore; -import org.mozilla.vrbrowser.audio.AudioEngine; -import org.mozilla.vrbrowser.audio.VRAudioTheme; -import org.mozilla.vrbrowser.ui.NavigationBarWidget; - -public class BrowserActivity extends Activity implements SessionStore.SessionChangeListener, WidgetManagerDelegate { - private static final String LOGTAG = "VRB"; - private static final int REQUEST_PERMISSIONS = 2; - /* package */ static final int REQUEST_FILE_PICKER = 1; - private FrameLayout mContainer; - private GeckoView mGeckoView; - private GeckoSession mGeckoSession; - private NavigationBarWidget mBrowserHeader; - private AudioEngine mAudioEngine; - - - @Override - protected void onCreate(Bundle savedInstanceState) { - Log.e(LOGTAG, "BrowserActivity onCreate"); - super.onCreate(savedInstanceState); - - SessionStore.get().setContext(this); - - mAudioEngine = new AudioEngine(this, new VRAudioTheme()); - mAudioEngine.preloadAsync(); - - setContentView(R.layout.browser_activity); - mBrowserHeader = findViewById(R.id.browserHeader); - EditText editText = findViewById(R.id.urlEditText); - editText.setShowSoftInputOnFocus(true); - editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_NEXT) { - String uri = textView.getText().toString(); - Log.e(LOGTAG, "Got URI: " + uri); - if (mGeckoSession != null) { - mGeckoSession.loadUri(uri); - } - setFullScreen(); - } - return false; - } - }); - - // Keep the screen on - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - mContainer = findViewById(R.id.container); - mGeckoView = findViewById(R.id.geckoview); - mGeckoView.coverUntilFirstPaint(Color.TRANSPARENT); - setContentView(mContainer); - loadFromIntent(getIntent()); - - SessionStore.get().addSessionChangeListener(this); - - } - - @Override - protected void onNewIntent(final Intent intent) { - super.onNewIntent(intent); - setIntent(intent); - final String action = intent.getAction(); - if (Intent.ACTION_VIEW.equals(action)) { - if (intent.getData() != null) { - loadFromIntent(intent); - } - } - } - - @Override - public void onBackPressed() { - if (SessionStore.get().canGoBack()) { - SessionStore.get().goBack(); - return; - } - super.onBackPressed(); - } - - @Override - protected void onPause() { - Log.e(LOGTAG, "BrowserActivity onPause"); - if (mGeckoView != null) { - mGeckoView.releaseSession(); - } - mAudioEngine.pauseEngine(); - super.onPause(); - } - - @Override - protected void onResume() { - Log.e(LOGTAG, "BrowserActivity onResume"); - if (mGeckoSession != null && mGeckoView != null) { - if (!mGeckoSession.equals(mGeckoView.getSession())) { - mGeckoView.releaseSession(); - mGeckoView.setSession(mGeckoSession); - } - mGeckoView.requestFocus(); - } - mAudioEngine.resumeEngine(); - super.onResume(); - } - - @Override - protected void onDestroy() { - Log.e(LOGTAG, "BrowserActivity onDestroy"); - if (mBrowserHeader != null) { - mBrowserHeader.releaseWidget(); - } - mAudioEngine.release(); - SessionStore.get().removeSessionChangeListener(this); - super.onDestroy(); - } - - @Override - protected void onActivityResult(final int requestCode, final int resultCode, - final Intent data) { - if (requestCode == REQUEST_FILE_PICKER) { - //final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt) - // mGeckoSession.getPromptDelegate(); - //prompt.onFileCallbackResult(resultCode, data); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - - @Override - public void onRequestPermissionsResult(final int requestCode, - final String[] permissions, - final int[] grantResults) { - Log.e(LOGTAG,"Got onRequestPermissionsResult"); - if (requestCode == REQUEST_PERMISSIONS && (mGeckoSession != null)) { - final MyGeckoViewPermission permission = (MyGeckoViewPermission) - mGeckoSession.getPermissionDelegate(); - permission.onRequestPermissionsResult(permissions, grantResults); - } else { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - } - } - - private void loadFromIntent(final Intent intent) { - final Uri uri = intent.getData(); - mGeckoSession = SessionStore.get().getCurrentSession(); - String uriValue; - if (mGeckoSession == null) { - int id = SessionStore.get().createSession(); - SessionStore.get().setCurrentSession(id); - mGeckoSession = SessionStore.get().getCurrentSession(); - final MyGeckoViewPermission permission = new MyGeckoViewPermission(); - permission.androidPermissionRequestCode = REQUEST_PERMISSIONS; - mGeckoSession.setPermissionDelegate(permission); - uriValue = (uri != null ? uri.toString() : SessionStore.get().getHomeUri()); - Log.e(LOGTAG, "BrowserActivity create session and load URI from intent: " + uriValue); - mGeckoSession.loadUri(uriValue); - mGeckoView.setSession(mGeckoSession); - } else if (uri != null) { - uriValue = uri.toString(); - Log.e(LOGTAG, "BrowserActivity load URI from intent: " + uriValue); - mGeckoSession.loadUri(uriValue); - } else { - uriValue = SessionStore.get().getCurrentUri(); - Log.e(LOGTAG, "BrowserActivity URI current session: " + uriValue); - } - } - - public void setFullScreen() { - int flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION - | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - - - getWindow().getDecorView().setSystemUiVisibility(flags); - } - - @Override - public void onNewSession(GeckoSession aSession, int aId) { - - } - - @Override - public void onRemoveSession(GeckoSession aSession, int aId) { - - } - - @Override - public void onCurrentSessionChange(GeckoSession aSession, int aId) { - if (aSession != mGeckoSession) { - if (mGeckoView.getSession() != null) { - mGeckoView.releaseSession(); - } - mGeckoView.setSession(aSession); - mGeckoSession = aSession; - } - } - - @Override - public int newWidgetHandle() { - return 0; - } - - @Override - public void addWidget(Widget aWidget) { - - } - - @Override - public void updateWidget(Widget aWidget) { - - } - - @Override - public void removeWidget(Widget aWidget) { - - } - - @Override - public void startWidgetResize(Widget aWidget) { - - } - - @Override - public void finishWidgetResize(Widget aWidget) { - - } - - @Override - public void addListener(Listener aListener) { - - } - - @Override - public void removeListener(Listener aListener) { - - } - - @Override - public void pushBackHandler(Runnable aRunnable) { - - } - - @Override - public void popBackHandler(Runnable aRunnable) { - - } - - @Override - public void fadeOutWorld() { - - } - - @Override - public void fadeInWorld() { - - } - - @Override - public void setTrayVisible(boolean visible) { - - } - - private class MyGeckoViewPermission implements GeckoSession.PermissionDelegate { - - int androidPermissionRequestCode = 1; - private Callback mCallback; - - void onRequestPermissionsResult(final String[] permissions, - final int[] grantResults) { - if (mCallback == null) { - return; - } - - final Callback cb = mCallback; - mCallback = null; - for (final int result : grantResults) { - if (result != PackageManager.PERMISSION_GRANTED) { - // At least one permission was not granted. - cb.reject(); - return; - } - } - Log.e(LOGTAG, "Permission Granted!"); - cb.grant(); - } - - @Override - public void onAndroidPermissionsRequest(final GeckoSession session, final String[] permissions, - final Callback callback) { - mCallback = callback; - requestPermissions(permissions, androidPermissionRequestCode); - } - - @Override - public void onContentPermissionRequest(final GeckoSession session, final String uri, - final int type, final String access, - final Callback callback) { -/* final int resId; - if ("geolocation".equals(type)) { - resId = R.string.request_geolocation; - } else if ("desktop-notification".equals(type)) { - resId = R.string.request_notification; - } else { - Log.w(LOGTAG, "Unknown permission: " + type); - callback.reject(); - return; - } - - final String title = getString(resId, Uri.parse(uri).getAuthority()); - final BasicGeckoViewPrompt prompt = (BasicGeckoViewPrompt) - mGeckoSession.getPromptDelegate(); - prompt.promptForPermission(session, title, callback);*/ - } - - @Override - public void onMediaPermissionRequest(GeckoSession geckoSession, String s, - MediaSource[] mediaSources, MediaSource[] mediaSources1, - MediaCallback mediaCallback) { - - } - - private void normalizeMediaName(final GeckoBundle[] sources) { -/* if (sources == null) { - return; - } - for (final GeckoBundle source : sources) { - final String mediaSource = source.getString("mediaSource"); - String name = source.getString("name"); - if ("camera".equals(mediaSource)) { - if (name.toLowerCase(Locale.ENGLISH).contains("front")) { - name = getString(R.string.media_front_camera); - } else { - name = getString(R.string.media_back_camera); - } - } else if (!name.isEmpty()) { - continue; - } else if ("microphone".equals(mediaSource)) { - name = getString(R.string.media_microphone); - } else { - name = getString(R.string.media_other); - } - source.putString("name", name); - }*/ - } - } -} diff --git a/app/src/main/cpp/vrb b/app/src/main/cpp/vrb index 439f056c87..870e8ff130 160000 --- a/app/src/main/cpp/vrb +++ b/app/src/main/cpp/vrb @@ -1 +1 @@ -Subproject commit 439f056c8767b15f46f5b4b5f279f45bcaab8e5e +Subproject commit 870e8ff13066914ee1fb08b504ab04b4160dbddb diff --git a/app/src/main/res/drawable/bookmark_background_color.xml b/app/src/main/res/drawable/bookmark_background_color.xml new file mode 100644 index 0000000000..e79537bf0a --- /dev/null +++ b/app/src/main/res/drawable/bookmark_background_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bookmark_description_color.xml b/app/src/main/res/drawable/bookmark_description_color.xml new file mode 100644 index 0000000000..a03ebe9872 --- /dev/null +++ b/app/src/main/res/drawable/bookmark_description_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bookmark_icon_color.xml b/app/src/main/res/drawable/bookmark_icon_color.xml new file mode 100644 index 0000000000..ec61112625 --- /dev/null +++ b/app/src/main/res/drawable/bookmark_icon_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bookmark_text_color.xml b/app/src/main/res/drawable/bookmark_text_color.xml new file mode 100644 index 0000000000..93a26e2d71 --- /dev/null +++ b/app/src/main/res/drawable/bookmark_text_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_icon_bookmark.xml b/app/src/main/res/drawable/ic_icon_bookmark.xml new file mode 100644 index 0000000000..50b9a81395 --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_bookmark.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_icon_bookmark_active.xml b/app/src/main/res/drawable/ic_icon_bookmark_active.xml new file mode 100644 index 0000000000..7b99b2e20d --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_bookmark_active.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_icon_bookmarks.xml b/app/src/main/res/drawable/ic_icon_bookmarks.xml new file mode 100644 index 0000000000..487becf891 --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_bookmarks.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_icon_trash.xml b/app/src/main/res/drawable/ic_icon_trash.xml new file mode 100644 index 0000000000..171534e1f9 --- /dev/null +++ b/app/src/main/res/drawable/ic_icon_trash.xml @@ -0,0 +1,5 @@ + + + + diff --git a/app/src/main/res/drawable/main_button_icon_color_active.xml b/app/src/main/res/drawable/main_button_icon_color_active.xml new file mode 100644 index 0000000000..7a2d8da429 --- /dev/null +++ b/app/src/main/res/drawable/main_button_icon_color_active.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/panel_background.xml b/app/src/main/res/drawable/panel_background.xml new file mode 100644 index 0000000000..186e314bbc --- /dev/null +++ b/app/src/main/res/drawable/panel_background.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_end.xml b/app/src/main/res/drawable/tray_background_end.xml new file mode 100644 index 0000000000..22ee1e6833 --- /dev/null +++ b/app/src/main/res/drawable/tray_background_end.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_end_active.xml b/app/src/main/res/drawable/tray_background_end_active.xml new file mode 100644 index 0000000000..653b97cf78 --- /dev/null +++ b/app/src/main/res/drawable/tray_background_end_active.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_end_private.xml b/app/src/main/res/drawable/tray_background_end_private.xml new file mode 100644 index 0000000000..7b927c687e --- /dev/null +++ b/app/src/main/res/drawable/tray_background_end_private.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_middle.xml b/app/src/main/res/drawable/tray_background_middle.xml new file mode 100644 index 0000000000..48dad7e37a --- /dev/null +++ b/app/src/main/res/drawable/tray_background_middle.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_middle_active.xml b/app/src/main/res/drawable/tray_background_middle_active.xml new file mode 100644 index 0000000000..e2dff8d115 --- /dev/null +++ b/app/src/main/res/drawable/tray_background_middle_active.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_middle_private.xml b/app/src/main/res/drawable/tray_background_middle_private.xml new file mode 100644 index 0000000000..77772000c8 --- /dev/null +++ b/app/src/main/res/drawable/tray_background_middle_private.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_start.xml b/app/src/main/res/drawable/tray_background_start.xml new file mode 100644 index 0000000000..4f525dfefb --- /dev/null +++ b/app/src/main/res/drawable/tray_background_start.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_start_active.xml b/app/src/main/res/drawable/tray_background_start_active.xml new file mode 100644 index 0000000000..806f7dec9e --- /dev/null +++ b/app/src/main/res/drawable/tray_background_start_active.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_background_start_private.xml b/app/src/main/res/drawable/tray_background_start_private.xml new file mode 100644 index 0000000000..4519f7c344 --- /dev/null +++ b/app/src/main/res/drawable/tray_background_start_private.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/tray_button_background.xml b/app/src/main/res/drawable/tray_button_background.xml deleted file mode 100644 index e1d8f7aebc..0000000000 --- a/app/src/main/res/drawable/tray_button_background.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/tray_button_background_private.xml b/app/src/main/res/drawable/tray_button_background_private.xml deleted file mode 100644 index 04c3178c78..0000000000 --- a/app/src/main/res/drawable/tray_button_background_private.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/drawable/url_button.xml b/app/src/main/res/drawable/url_button.xml index 73228080f6..31b43387aa 100644 --- a/app/src/main/res/drawable/url_button.xml +++ b/app/src/main/res/drawable/url_button.xml @@ -1,13 +1,17 @@ + + + + + - + - - + diff --git a/app/src/main/res/drawable/url_button_end.xml b/app/src/main/res/drawable/url_button_end.xml new file mode 100644 index 0000000000..4360f6f1c9 --- /dev/null +++ b/app/src/main/res/drawable/url_button_end.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/url_button_icon_color.xml b/app/src/main/res/drawable/url_button_icon_color.xml index 529f01d8e1..af1298c814 100644 --- a/app/src/main/res/drawable/url_button_icon_color.xml +++ b/app/src/main/res/drawable/url_button_icon_color.xml @@ -1,4 +1,6 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/bookmarks.xml b/app/src/main/res/layout/bookmarks.xml new file mode 100644 index 0000000000..42b3424b36 --- /dev/null +++ b/app/src/main/res/layout/bookmarks.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/browser_activity.xml b/app/src/main/res/layout/browser_activity.xml deleted file mode 100644 index 791eb74ec8..0000000000 --- a/app/src/main/res/layout/browser_activity.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/choice_prompt.xml b/app/src/main/res/layout/choice_prompt.xml index 763589c5cf..f2a8b4aafb 100644 --- a/app/src/main/res/layout/choice_prompt.xml +++ b/app/src/main/res/layout/choice_prompt.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/list_popup_window.xml b/app/src/main/res/layout/list_popup_window.xml index c3f67e3da4..88b4198b9e 100644 --- a/app/src/main/res/layout/list_popup_window.xml +++ b/app/src/main/res/layout/list_popup_window.xml @@ -1,5 +1,5 @@ - @@ -19,4 +19,4 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.0" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_url.xml b/app/src/main/res/layout/navigation_url.xml index 797569660c..18f5608ca8 100644 --- a/app/src/main/res/layout/navigation_url.xml +++ b/app/src/main/res/layout/navigation_url.xml @@ -1,60 +1,91 @@ - - + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/noapi_layout.xml b/app/src/main/res/layout/noapi_layout.xml index 5a1b7e37a4..15e32f628f 100644 --- a/app/src/main/res/layout/noapi_layout.xml +++ b/app/src/main/res/layout/noapi_layout.xml @@ -1,7 +1,6 @@ - @@ -106,4 +105,4 @@ android:src="@drawable/ic_keyboard_arrow_down_black_24px" /> - + diff --git a/app/src/main/res/layout/tray.xml b/app/src/main/res/layout/tray.xml index 298eea6bda..9beeec39ac 100644 --- a/app/src/main/res/layout/tray.xml +++ b/app/src/main/res/layout/tray.xml @@ -1,34 +1,36 @@ - + + + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center"> - - + + - + + - + + - + style="@style/trayButtonMiddleTheme" + android:src="@drawable/ic_tray_settings" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/voice_search_dialog.xml b/app/src/main/res/layout/voice_search_dialog.xml index b8799b8c9e..7b58630cb1 100644 --- a/app/src/main/res/layout/voice_search_dialog.xml +++ b/app/src/main/res/layout/voice_search_dialog.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 923636191b..0e7db8ee8e 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -15,7 +15,9 @@ + + diff --git a/app/src/main/res/values/dimen.xml b/app/src/main/res/values/dimen.xml index cc37a20bdb..d70256653e 100644 --- a/app/src/main/res/values/dimen.xml +++ b/app/src/main/res/values/dimen.xml @@ -4,14 +4,16 @@ 800px - 4.0 - 0.2 - -4.2 + 4.0 + 0.2 + -4.2 1.5 720dp - 45dp + 44dp + 24dp + 44dp 2.4 @@ -85,8 +87,8 @@ -0.25 -3.5 - 1.0 - 120dp + 1.2 + 160dp 40dp @@ -133,9 +135,9 @@ 10dip - 4.0 + 4 250dp - 1.3 + 1.25 0.15 0.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 5da450749f..9372c463a2 100644 --- a/app/src/main/res/values/non_L10n.xml +++ b/app/src/main/res/values/non_L10n.xml @@ -34,6 +34,7 @@ org.mozilla.vrbrowser.CRASH_RECEIVER_PERMISSION x FirefoxReality + about:bookmarks https://location.services.mozilla.com/v1/country diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d6cab708c6..f9b6627dea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -489,5 +489,4 @@ Remove All - diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 0ba23ed134..d02a8f2736 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -9,9 +9,7 @@ - - @@ -42,6 +40,7 @@ fitCenter @drawable/main_button_icon_color @drawable/main_button_icon_color_private + @drawable/main_button_icon_color_active - + + + + + +