summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoey Rizzoli <joey@lineageos.org>2017-04-20 21:36:40 +0200
committerJoey Rizzoli <joey@lineageos.org>2017-04-20 21:38:16 +0200
commit60de8781c2bf6ebfdbfd51d2657a715ce5a5f2ff (patch)
treea05b72007bbfab536611ec6c84b513220640b0dd
parentc11c303e26a04ef128a7811d9a246de0543e007d (diff)
downloadandroid_packages_apps_Jelly-60de8781c2bf6ebfdbfd51d2657a715ce5a5f2ff.tar.gz
android_packages_apps_Jelly-60de8781c2bf6ebfdbfd51d2657a715ce5a5f2ff.tar.bz2
android_packages_apps_Jelly-60de8781c2bf6ebfdbfd51d2657a715ce5a5f2ff.zip
Initial push
Signed-off-by: Joey Rizzoli <joey@lineageos.org>
-rw-r--r--.gitignore3
-rw-r--r--app/.gitignore1
-rw-r--r--app/build.gradle36
-rw-r--r--app/proguard-rules.pro25
-rw-r--r--app/src/main/AndroidManifest.xml95
-rw-r--r--app/src/main/java/org/lineageos/jelly/MainActivity.java395
-rw-r--r--app/src/main/java/org/lineageos/jelly/SettingsActivity.java66
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/Favorite.java64
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java155
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java77
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java105
-rw-r--r--app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java58
-rw-r--r--app/src/main/java/org/lineageos/jelly/history/HistoryActivity.java146
-rw-r--r--app/src/main/java/org/lineageos/jelly/history/HistoryAdapter.java78
-rw-r--r--app/src/main/java/org/lineageos/jelly/history/HistoryDatabaseHandler.java96
-rw-r--r--app/src/main/java/org/lineageos/jelly/history/HistoryHolder.java89
-rw-r--r--app/src/main/java/org/lineageos/jelly/history/HistoryItem.java50
-rw-r--r--app/src/main/java/org/lineageos/jelly/ui/EditTextExt.java78
-rw-r--r--app/src/main/java/org/lineageos/jelly/utils/PrefsUtils.java71
-rw-r--r--app/src/main/java/org/lineageos/jelly/utils/UiUtils.java88
-rw-r--r--app/src/main/java/org/lineageos/jelly/utils/UrlUtils.java84
-rw-r--r--app/src/main/java/org/lineageos/jelly/webview/ChromeClient.java104
-rw-r--r--app/src/main/java/org/lineageos/jelly/webview/WebClient.java53
-rw-r--r--app/src/main/java/org/lineageos/jelly/webview/WebViewExt.java141
-rw-r--r--app/src/main/res/drawable/empty_background.xml24
-rw-r--r--app/src/main/res/drawable/ic_back.xml24
-rw-r--r--app/src/main/res/drawable/ic_delete.xml24
-rw-r--r--app/src/main/res/drawable/ic_download.xml24
-rw-r--r--app/src/main/res/drawable/ic_favorite.xml24
-rw-r--r--app/src/main/res/drawable/ic_favorite_add.xml24
-rw-r--r--app/src/main/res/drawable/ic_history.xml24
-rw-r--r--app/src/main/res/drawable/ic_incognito.xml25
-rw-r--r--app/src/main/res/drawable/ic_menu.xml24
-rw-r--r--app/src/main/res/drawable/ic_new_tab.xml24
-rw-r--r--app/src/main/res/drawable/ic_refresh.xml24
-rw-r--r--app/src/main/res/drawable/ic_settings.xml24
-rw-r--r--app/src/main/res/drawable/ic_share.xml24
-rw-r--r--app/src/main/res/drawable/ic_shortcut.xml24
-rw-r--r--app/src/main/res/layout/activity_favorites.xml57
-rw-r--r--app/src/main/res/layout/activity_history.xml55
-rw-r--r--app/src/main/res/layout/activity_main.xml70
-rw-r--r--app/src/main/res/layout/activity_settings.xml33
-rw-r--r--app/src/main/res/layout/dialog_favorite_edit.xml51
-rw-r--r--app/src/main/res/layout/item_favorite.xml38
-rw-r--r--app/src/main/res/layout/item_history.xml40
-rw-r--r--app/src/main/res/layout/search_bar.xml73
-rw-r--r--app/src/main/res/layout/sheet_actions.xml78
-rw-r--r--app/src/main/res/menu/menu_history.xml24
-rw-r--r--app/src/main/res/menu/menu_main.xml63
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 4323 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2680 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 6182 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 9899 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 13851 bytes
-rw-r--r--app/src/main/res/values/colors.xml34
-rw-r--r--app/src/main/res/values/search_engines.xml33
-rw-r--r--app/src/main/res/values/strings.xml136
-rw-r--r--app/src/main/res/values/styles.xml94
-rw-r--r--app/src/main/res/xml/backup_descriptor.xml29
-rw-r--r--app/src/main/res/xml/file_provider.xml20
-rw-r--r--app/src/main/res/xml/settings.xml65
-rw-r--r--build.gradle23
-rw-r--r--gradle.properties17
-rw-r--r--gradle/wrapper/gradle-wrapper.jarbin0 -> 53636 bytes
-rw-r--r--gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xgradlew160
-rw-r--r--gradlew.bat90
-rw-r--r--settings.gradle1
68 files changed, 3783 insertions, 2 deletions
diff --git a/.gitignore b/.gitignore
index 39fb081..09b993d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,7 @@
*.iml
.gradle
/local.properties
-/.idea/workspace.xml
-/.idea/libraries
+/.idea
.DS_Store
/build
/captures
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..16834b8
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,36 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.2"
+ defaultConfig {
+ applicationId "org.lineageos.jelly"
+ minSdkVersion 23
+ targetSdkVersion 25
+ versionCode 1
+ versionName "1.0"
+ jackOptions.enabled true
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ lintOptions {
+ disable 'RestrictedApi'
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.android.support:appcompat-v7:25.3.1'
+ compile 'com.android.support:design:25.3.1'
+ compile 'com.android.support:cardview-v7:25.3.1'
+ compile 'com.android.support:palette-v7:25.3.1'
+ compile 'com.android.support:support-v4:25.3.1'
+}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..5f7e87d
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,25 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/joey/android/android-sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+ public *;
+}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..a2875f9
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.lineageos.jelly">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
+
+ <application
+ android:allowBackup="true"
+ android:fullBackupContent="@xml/backup_descriptor"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme">
+
+ <activity
+ android:name="org.lineageos.jelly.MainActivity"
+ android:documentLaunchMode="always"
+ android:hardwareAccelerated="true"
+ android:label="@string/app_name"
+ android:persistent="true"
+ android:theme="@style/AppTheme.NoActionBar"
+ android:windowSoftInputMode="stateHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:mimeType="text/html" />
+ <data android:mimeType="text/plain" />
+ <data android:mimeType="application/xhtml+xml" />
+ <data android:mimeType="application/vnd.wap.xhtml+xml" />
+ </intent-filter>
+ </activity>
+
+ <activity
+ android:name="org.lineageos.jelly.history.HistoryActivity"
+ android:label="@string/history_title"
+ android:theme="@style/AppTheme.NoActionBar" />
+
+ <activity
+ android:name="org.lineageos.jelly.favorite.FavoriteActivity"
+ android:label="@string/favorite_title"
+ android:theme="@style/AppTheme.NoActionBar" />
+
+ <activity
+ android:name="org.lineageos.jelly.SettingsActivity"
+ android:label="@string/settings_title"
+ android:theme="@style/AppTheme.NoActionBar" />
+
+ <provider
+ android:name="android.support.v4.content.FileProvider"
+ android:authorities="org.lineageos.jelly.fileprovider"
+ android:exported="false"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_provider" />
+ </provider>
+ </application>
+</manifest>
diff --git a/app/src/main/java/org/lineageos/jelly/MainActivity.java b/app/src/main/java/org/lineageos/jelly/MainActivity.java
new file mode 100644
index 0000000..75793fc
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/MainActivity.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly;
+
+import android.Manifest;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.DownloadManager;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.ColorDrawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.support.design.widget.BottomSheetDialog;
+import android.support.design.widget.CoordinatorLayout;
+import android.support.design.widget.Snackbar;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.content.FileProvider;
+import android.support.v4.widget.SwipeRefreshLayout;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.view.menu.MenuBuilder;
+import android.support.v7.view.menu.MenuPopupHelper;
+import android.support.v7.widget.PopupMenu;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.view.ContextThemeWrapper;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.webkit.CookieManager;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+
+import org.lineageos.jelly.favorite.Favorite;
+import org.lineageos.jelly.favorite.FavoriteActivity;
+import org.lineageos.jelly.favorite.FavoriteDatabaseHandler;
+import org.lineageos.jelly.history.HistoryActivity;
+import org.lineageos.jelly.utils.PrefsUtils;
+import org.lineageos.jelly.utils.UiUtils;
+import org.lineageos.jelly.webview.WebViewExt;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class MainActivity extends AppCompatActivity {
+ public static final int FILE_CHOOSER_REQ = 421;
+ private static final String TAG = MainActivity.class.getSimpleName();
+ private static final String PROVIDER = "org.lineageos.jelly.fileprovider";
+ private static final String EXTRA_INCOGNITO = "extra_incognito";
+ private static final int STORAGE_PERM_REQ = 423;
+ private static final int LOCATION_PERM_REQ = 424;
+
+ private CoordinatorLayout mCoordinator;
+ private WebViewExt mWebView;
+
+ private Bitmap mUrlIcon;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_main);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ mCoordinator = (CoordinatorLayout) findViewById(R.id.coordinator_layout);
+ SwipeRefreshLayout refreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe_refresh);
+ refreshLayout.setOnRefreshListener(() -> {
+ mWebView.reload();
+ new Handler().postDelayed(() -> refreshLayout.setRefreshing(false), 1000);
+ });
+ ProgressBar progressBar = (ProgressBar) findViewById(R.id.load_progress);
+ EditText editText = (EditText) findViewById(R.id.url_bar);
+ editText.setOnKeyListener((v, keyCode, event) -> {
+ if (event.getAction() != KeyEvent.ACTION_DOWN) {
+ return true;
+ }
+
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_ENTER:
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_NUMPAD_ENTER:
+ mWebView.loadUrl(editText.getText().toString());
+ break;
+ }
+ return true;
+ });
+
+ Intent intent = getIntent();
+ String url = intent.getDataString();
+ boolean incognito = intent.getBooleanExtra(EXTRA_INCOGNITO, false);
+
+ // Make sure prefs are set before loading them
+ PreferenceManager.setDefaultValues(this, R.xml.settings, false);
+
+ setupMenu();
+ mWebView = (WebViewExt) findViewById(R.id.web_view);
+ mWebView.init(this, editText, progressBar, incognito);
+ mWebView.loadUrl(url == null ? PrefsUtils.getHomePage(this) : url);
+ }
+
+ @Override
+ protected void onResume() {
+ CookieManager.setAcceptFileSchemeCookies(PrefsUtils.getCookie(this));
+
+ super.onResume();
+ if (PrefsUtils.getLookLock(this)) {
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
+ WindowManager.LayoutParams.FLAG_SECURE);
+ } else {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE);
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mWebView.canGoBack()) {
+ mWebView.goBack();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] results) {
+ switch (requestCode) {
+ case LOCATION_PERM_REQ:
+ if (hasLocationPermission()) {
+ mWebView.reload();
+ }
+ break;
+ case STORAGE_PERM_REQ:
+ if (hasStoragePermission()) {
+ if (shouldShowRequestPermissionRationale(
+ Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.permission_error_title)
+ .setMessage(R.string.permission_error_storage)
+ .setCancelable(false)
+ .setPositiveButton(getString(R.string.permission_error_ask_again),
+ ((dialog, which) -> requestStoragePermission()))
+ .setNegativeButton(getString(R.string.dismiss),
+ (((dialog, which) -> dialog.dismiss())))
+ .show();
+ } else {
+ Snackbar.make(mCoordinator, getString(R.string.permission_error_forever),
+ Snackbar.LENGTH_LONG).show();
+ }
+ }
+ break;
+ }
+
+ }
+
+ private void setupMenu() {
+ ImageButton menu = (ImageButton) findViewById(R.id.search_menu);
+ menu.setOnClickListener(v -> {
+ ContextThemeWrapper wrapper = new ContextThemeWrapper(this,
+ R.style.AppTheme_PopupMenuOverlapAnchor);
+
+ PopupMenu popupMenu = new PopupMenu(wrapper, menu, Gravity.NO_GRAVITY,
+ R.attr.actionOverflowMenuStyle, 0);
+ popupMenu.inflate(R.menu.menu_main);
+ popupMenu.setOnMenuItemClickListener(item -> {
+ switch (item.getItemId()) {
+ case R.id.menu_new:
+ openInNewTab(null);
+ break;
+ case R.id.menu_incognito:
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.putExtra(EXTRA_INCOGNITO, true);
+ startActivity(intent);
+ break;
+ case R.id.menu_reload:
+ mWebView.reload();
+ break;
+ case R.id.menu_add_favorite:
+ setAsFavorite(mWebView.getTitle(), mWebView.getUrl());
+ break;
+ case R.id.menu_share:
+ // Delay a bit to allow popup menu hide animation to play
+ new Handler().postDelayed(() -> shareUrl(mWebView.getUrl()), 300);
+ break;
+ case R.id.menu_favorite:
+ startActivity(new Intent(this, FavoriteActivity.class));
+ break;
+ case R.id.menu_history:
+ startActivity(new Intent(this, HistoryActivity.class));
+ break;
+ case R.id.menu_shortcut:
+ addShortcut();
+ break;
+ case R.id.menu_settings:
+ startActivity(new Intent(this, SettingsActivity.class));
+ break;
+ }
+ return true;
+ });
+
+ // Fuck you, lint
+ //noinspection RestrictedApi
+ MenuPopupHelper helper = new MenuPopupHelper(wrapper,
+ (MenuBuilder) popupMenu.getMenu(), menu);
+ //noinspection RestrictedApi
+ helper.setForceShowIcon(true);
+ //noinspection RestrictedApi
+ helper.show();
+ });
+ }
+
+ private void openInNewTab(String url) {
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.setData(Uri.parse(url));
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ startActivity(intent);
+ }
+
+ private void shareUrl(String url) {
+ Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.putExtra(Intent.EXTRA_TEXT, url);
+
+ if (PrefsUtils.getAdvancedShare(this) && url.equals(mWebView.getUrl())) {
+ try {
+ File file = new File(getCacheDir(),
+ String.valueOf(System.currentTimeMillis()) + ".png");
+ FileOutputStream out = new FileOutputStream(file);
+ Bitmap bm = mWebView.getSnap();
+ if (bm == null) {
+ return;
+ }
+ bm.compress(Bitmap.CompressFormat.PNG, 70, out);
+ out.flush();
+ out.close();
+ intent.putExtra(Intent.EXTRA_STREAM,
+ FileProvider.getUriForFile(this, PROVIDER, file));
+ intent.setType("image/png");
+ intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ } catch (IOException e) {
+ Log.e(TAG, e.getMessage());
+ }
+ } else {
+ intent.setType("text/plain");
+ }
+
+ startActivity(intent);
+ }
+
+ private void setAsFavorite(String title, String url) {
+ FavoriteDatabaseHandler handler = new FavoriteDatabaseHandler(this);
+ boolean hasValidIcon = mUrlIcon != null && !mUrlIcon.isRecycled();
+ handler.addItem(new Favorite(title, url, hasValidIcon ?
+ UiUtils.getColor(this, mUrlIcon, false) :
+ ContextCompat.getColor(this, R.color.colorAccent)));
+ Snackbar.make(mCoordinator, getString(R.string.favorite_added),
+ Snackbar.LENGTH_LONG).show();
+ }
+
+ public void downloadFileAsk(String url, String fileName) {
+ if (!hasStoragePermission()) {
+ requestStoragePermission();
+ return;
+ }
+
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.download_title)
+ .setMessage(getString(R.string.download_message, fileName))
+ .setPositiveButton(getString(R.string.download_positive),
+ (dialog, which) -> fetchFile(url, fileName))
+ .setNegativeButton(getString(R.string.dismiss),
+ ((dialog, which) -> dialog.dismiss()))
+ .show();
+ }
+
+ private void fetchFile(String url, String fileName) {
+ DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
+ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
+ DownloadManager manager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
+ manager.enqueue(request);
+ }
+
+ public void showSheetMenu(String url, boolean shouldAllowDownload) {
+ final BottomSheetDialog sheet = new BottomSheetDialog(this);
+
+ @SuppressLint("InflateParams")
+ View view = getLayoutInflater().inflate(R.layout.sheet_actions, null);
+ View tabLayout = view.findViewById(R.id.sheet_new_tab);
+ View shareLayout = view.findViewById(R.id.sheet_share);
+ View favouriteLayout = view.findViewById(R.id.sheet_favourite);
+ View downloadLayout = view.findViewById(R.id.sheet_download);
+
+ tabLayout.setOnClickListener(v -> openInNewTab(url));
+ shareLayout.setOnClickListener(v -> shareUrl(url));
+ favouriteLayout.setOnClickListener(v -> setAsFavorite(url, url));
+ if (shouldAllowDownload) {
+ downloadLayout.setOnClickListener(v -> downloadFileAsk(url, ""));
+ downloadLayout.setVisibility(View.VISIBLE);
+ }
+ sheet.setContentView(view);
+ sheet.show();
+ }
+
+ private void requestStoragePermission() {
+ String[] permissionArray = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE};
+ requestPermissions(permissionArray, STORAGE_PERM_REQ);
+ }
+
+ private boolean hasStoragePermission() {
+ int result = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+ return result == PackageManager.PERMISSION_GRANTED;
+ }
+
+ public void requestLocationPermission() {
+ String[] permissionArray = new String[]{Manifest.permission.ACCESS_FINE_LOCATION};
+ requestPermissions(permissionArray, LOCATION_PERM_REQ);
+ }
+
+ public boolean hasLocationPermission() {
+ int result = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
+ return result == PackageManager.PERMISSION_GRANTED;
+ }
+
+ public void setColor(Bitmap favicon, boolean incognito) {
+ ActionBar actionBar = getSupportActionBar();
+ if (favicon == null || favicon.isRecycled() || actionBar == null) {
+ return;
+ }
+
+ mUrlIcon = favicon.copy(favicon.getConfig(), true);
+ int color = UiUtils.getColor(this, favicon, incognito);
+ actionBar.setBackgroundDrawable(new ColorDrawable(color));
+ getWindow().setStatusBarColor(color);
+
+ int flags = getWindow().getDecorView().getSystemUiVisibility();
+ if (UiUtils.isColorLight(color)) {
+ flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ } else {
+ flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ getWindow().getDecorView().setSystemUiVisibility(flags);
+
+ setTaskDescription(new ActivityManager.TaskDescription(mWebView.getTitle(),
+ favicon, color));
+
+ if (!favicon.isRecycled()) {
+ favicon.recycle();
+ }
+ }
+
+ private void addShortcut() {
+ Intent intent = new Intent(this, MainActivity.class);
+ intent.setData(Uri.parse(mWebView.getUrl()));
+ intent.setAction(Intent.ACTION_MAIN);
+
+ Bitmap icon = mUrlIcon == null ?
+ BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher) : mUrlIcon;
+ Bitmap launcherIcon = UiUtils.getShortcutIcon(this, icon);
+
+ Intent addIntent = new Intent();
+ addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, mWebView.getTitle());
+ addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, launcherIcon);
+ addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent);
+ addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
+ sendBroadcast(addIntent);
+ launcherIcon.recycle();
+ Snackbar.make(mCoordinator, getString(R.string.shortcut_added),
+ Snackbar.LENGTH_LONG).show();
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/SettingsActivity.java b/app/src/main/java/org/lineageos/jelly/SettingsActivity.java
new file mode 100644
index 0000000..aa57a55
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/SettingsActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly;
+
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.PreferenceFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.View;
+
+// "noSuchMethodError" is thrown if lambda is used in this class (wtf)
+@SuppressWarnings("Convert2Lambda")
+public class SettingsActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_settings);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ toolbar.setNavigationIcon(R.drawable.ic_back);
+ toolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ finish();
+ }
+ });
+ }
+
+ public static class MyPreferenceFragment extends PreferenceFragment {
+
+ @Override
+ public void onCreate(Bundle savedInstance) {
+ super.onCreate(savedInstance);
+ addPreferencesFromResource(R.xml.settings);
+
+ Preference homePage = findPreference("key_home_page");
+ homePage.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ homePage.setSummary(newValue.toString());
+ return true;
+ }
+ });
+ if (homePage.getSummary() == null) {
+ homePage.setSummary(getString(R.string.default_home_page));
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/Favorite.java b/app/src/main/java/org/lineageos/jelly/favorite/Favorite.java
new file mode 100644
index 0000000..9f0096d
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/favorite/Favorite.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.favorite;
+
+public class Favorite {
+ private long id = -1;
+ private String title;
+ private String url;
+ private int color;
+
+ public Favorite(String title, String url, int color) {
+ this.title = title;
+ this.url = url;
+ this.color = color;
+ }
+
+ Favorite(long id, String title, String url, int color) {
+ this.id = id;
+ this.title = title;
+ this.url = url;
+ this.color = color;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ String getUrl() {
+ return url;
+ }
+
+ void setUrl(String url) {
+ this.url = url;
+ }
+
+ public int getColor() {
+ return color;
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java
new file mode 100644
index 0000000..c8d8bbd
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteActivity.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.favorite;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+
+import org.lineageos.jelly.R;
+import org.lineageos.jelly.utils.UiUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class FavoriteActivity extends AppCompatActivity {
+ private RecyclerView mList;
+ private View mEmptyView;
+
+ private FavoriteDatabaseHandler mDbHandler;
+ private FavoriteAdapter mAdapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstance) {
+ super.onCreate(savedInstance);
+
+ setContentView(R.layout.activity_favorites);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ toolbar.setNavigationIcon(R.drawable.ic_back);
+ toolbar.setNavigationOnClickListener(v -> finish());
+
+ mList = (RecyclerView) findViewById(R.id.favorite_list);
+ mEmptyView = findViewById(R.id.favorite_empty_layout);
+
+ mDbHandler = new FavoriteDatabaseHandler(this);
+ mAdapter = new FavoriteAdapter(this, new ArrayList<>());
+ mList.setLayoutManager(new GridLayoutManager(this, 2));
+ mList.setItemAnimator(new DefaultItemAnimator());
+ mList.setAdapter(mAdapter);
+
+ int listTop = mList.getTop();
+ mList.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ super.onScrolled(recyclerView, dx, dy);
+
+ toolbar.setElevation(recyclerView.getChildAt(0).getTop() < listTop ?
+ UiUtils.dpToPx(getResources(), 8) : 0);
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ refresh();
+ }
+
+ void refresh() {
+ List<Favorite> items = mDbHandler.getAllItems();
+ // Reverse database list order
+ Collections.reverse(items);
+ mAdapter.updateList(items);
+
+ if (items.isEmpty()) {
+ mList.setVisibility(View.GONE);
+ mEmptyView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ boolean editItem(Favorite item) {
+ @SuppressLint("InflateParams")
+ View view = LayoutInflater.from(this).inflate(R.layout.dialog_favorite_edit, null);
+ EditText titleEdit = (EditText) view.findViewById(R.id.favorite_edit_title);
+ EditText urlEdit = (EditText) view.findViewById(R.id.favorite_edit_url);
+
+ titleEdit.setText(item.getTitle());
+ urlEdit.setText(item.getUrl());
+
+ String error = getString(R.string.favorite_edit_error);
+ urlEdit.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ if (!s.toString().contains("http")) {
+ urlEdit.setError(error);
+ }
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (!s.toString().contains("http")) {
+ urlEdit.setError(error);
+ }
+ }
+ });
+
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.favorite_edit_dialog_title)
+ .setView(view)
+ .setPositiveButton(R.string.favorite_edit_positive,
+ ((dialog, which) -> {
+ String url = urlEdit.getText().toString();
+ String title = titleEdit.getText().toString();
+ if (url.isEmpty()) {
+ urlEdit.setError(error);
+ urlEdit.requestFocus();
+ }
+ item.setTitle(title);
+ item.setUrl(url);
+ mDbHandler.updateItem(item);
+ refresh();
+ dialog.dismiss();
+ }))
+ .setNeutralButton(R.string.favorite_edit_delete,
+ (dialog, which) -> {
+ mDbHandler.deleteItem(item.getId());
+ mAdapter.removeItem(item.getId());
+ dialog.dismiss();
+ })
+ .setNegativeButton(android.R.string.cancel,
+ (dialog, which) -> dialog.dismiss())
+ .show();
+ return true;
+ }
+
+}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java
new file mode 100644
index 0000000..e315f75
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteAdapter.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.favorite;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import org.lineageos.jelly.R;
+
+import java.util.List;
+
+class FavoriteAdapter extends RecyclerView.Adapter<FavoriteHolder> {
+ private final Context mContext;
+ private List<Favorite> mList;
+
+ FavoriteAdapter(Context context, List<Favorite> list) {
+ mContext = context;
+ mList = list;
+ }
+
+ @Override
+ public FavoriteHolder onCreateViewHolder(ViewGroup parent, int type) {
+ return new FavoriteHolder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_favorite, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(FavoriteHolder holder, int position) {
+ holder.setData(mContext, mList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mList.size();
+ }
+
+ void updateList(List<Favorite> list) {
+ mList = list;
+ notifyDataSetChanged();
+ }
+
+ void removeItem(long id) {
+ int position = 0;
+ for (; position < mList.size(); position++) {
+ if (mList.get(position).getId() == id) {
+ break;
+ }
+ }
+
+ if (position == mList.size()) {
+ return;
+ }
+
+ mList.remove(position);
+ notifyItemRemoved(position);
+
+ if (mList.isEmpty()) {
+ // Show empty status
+ ((FavoriteActivity) mContext).refresh();
+ }
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java
new file mode 100644
index 0000000..e54537b
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteDatabaseHandler.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.favorite;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class FavoriteDatabaseHandler extends SQLiteOpenHelper {
+ private static final int DB_VERSION = 1;
+ private static final String DB_NAME = "FavoriteDatabase";
+ private static final String DB_TABLE_FAVORITES = "favorites";
+ private static final String KEY_ID = "id";
+ private static final String KEY_TITLE = "title";
+ private static final String KEY_URL = "url";
+ private static final String KEY_COLOR = "color";
+
+
+ public FavoriteDatabaseHandler(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + DB_TABLE_FAVORITES + " (" +
+ KEY_ID + " INTEGER PRIMARY KEY, " +
+ KEY_TITLE + " TEXT, " +
+ KEY_URL + " TEXT, " +
+ KEY_COLOR + " INTEGER)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // Update this when db table will be changed
+ }
+
+ public void addItem(Favorite item) {
+ if (item.getId() == -1) {
+ item.setId(System.currentTimeMillis());
+ }
+
+ ContentValues values = new ContentValues();
+ values.put(KEY_ID, item.getId());
+ values.put(KEY_TITLE, item.getTitle());
+ values.put(KEY_URL, item.getUrl());
+ values.put(KEY_COLOR, item.getColor());
+
+ SQLiteDatabase db = getWritableDatabase();
+ db.insert(DB_TABLE_FAVORITES, null, values);
+ db.close();
+ }
+
+ void updateItem(Favorite item) {
+ SQLiteDatabase db = getWritableDatabase();
+
+ ContentValues values = new ContentValues();
+ values.put(KEY_TITLE, item.getTitle());
+ values.put(KEY_URL, item.getUrl());
+ values.put(KEY_COLOR, item.getColor());
+
+ db.update(DB_TABLE_FAVORITES, values, KEY_ID + "=?",
+ new String[]{String.valueOf(item.getId())});
+ }
+
+ void deleteItem(long id) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.delete(DB_TABLE_FAVORITES, KEY_ID + "=?", new String[]{String.valueOf(id)});
+ db.close();
+ }
+
+ List<Favorite> getAllItems() {
+ List<Favorite> list = new ArrayList<>();
+ SQLiteDatabase db = getWritableDatabase();
+ Cursor cursor = db.rawQuery("SELECT * FROM " + DB_TABLE_FAVORITES, null);
+
+ if (cursor.moveToFirst()) {
+ do {
+ list.add(new Favorite(Long.parseLong(cursor.getString(0)),
+ cursor.getString(1), cursor.getString(2),
+ Integer.parseInt(cursor.getString(3))));
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ db.close();
+ return list;
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java
new file mode 100644
index 0000000..ffc2726
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/favorite/FavoriteHolder.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.favorite;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.net.Uri;
+import android.support.v7.widget.CardView;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.TextView;
+
+import org.lineageos.jelly.MainActivity;
+import org.lineageos.jelly.R;
+import org.lineageos.jelly.utils.UiUtils;
+
+class FavoriteHolder extends RecyclerView.ViewHolder {
+ private final CardView mCard;
+ private final TextView mTitle;
+
+ FavoriteHolder(View view) {
+ super(view);
+ mCard = (CardView) view.findViewById(R.id.row_favorite_card);
+ mTitle = (TextView) view.findViewById(R.id.row_favorite_title);
+ }
+
+ void setData(Context context, Favorite item) {
+ String title = item.getTitle();
+ if (title == null || title.isEmpty()) {
+ title = item.getUrl().split("/")[2];
+ }
+ mTitle.setText(title);
+ mTitle.setTextColor(UiUtils.isColorLight(item.getColor()) ? Color.BLACK : Color.WHITE);
+ mCard.setCardBackgroundColor(item.getColor());
+
+ mCard.setOnClickListener(v -> {
+ Intent intent = new Intent(context, MainActivity.class);
+ intent.setData(Uri.parse(item.getUrl()));
+ context.startActivity(intent);
+ });
+
+ mCard.setOnLongClickListener(v -> ((FavoriteActivity) context).editItem(item));
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/history/HistoryActivity.java b/app/src/main/java/org/lineageos/jelly/history/HistoryActivity.java
new file mode 100644
index 0000000..03cb994
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/history/HistoryActivity.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.history;
+
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.DefaultItemAnimator;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+import org.lineageos.jelly.R;
+import org.lineageos.jelly.utils.UiUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class HistoryActivity extends AppCompatActivity {
+ private RecyclerView mList;
+ private View mEmptyView;
+
+ private HistoryDatabaseHandler mDbHandler;
+ private HistoryAdapter mAdapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstance) {
+ super.onCreate(savedInstance);
+
+ setContentView(R.layout.activity_history);
+
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ toolbar.setNavigationIcon(R.drawable.ic_back);
+ toolbar.setNavigationOnClickListener(v -> finish());
+
+ mList = (RecyclerView) findViewById(R.id.history_list);
+ mEmptyView = findViewById(R.id.history_empty_layout);
+
+ mDbHandler = new HistoryDatabaseHandler(this);
+ mAdapter = new HistoryAdapter(this, new ArrayList<>());
+ mList.setLayoutManager(new LinearLayoutManager(this));
+ mList.setItemAnimator(new DefaultItemAnimator());
+ mList.setAdapter(mAdapter);
+
+ int listTop = mList.getTop();
+ mList.addOnScrollListener(new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+ super.onScrolled(recyclerView, dx, dy);
+
+ toolbar.setElevation(recyclerView.getChildAt(0).getTop() < listTop ?
+ UiUtils.dpToPx(getResources(), 8) : 0);
+ }
+ });
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ refresh();
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.menu_history, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() != R.id.menu_history_delete) {
+ return super.onOptionsItemSelected(item);
+ }
+
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.history_delete_title)
+ .setMessage(R.string.history_delete_message)
+ .setPositiveButton(R.string.history_delete_positive,
+ (dialog, which) -> deleteAll())
+ .setNegativeButton(android.R.string.cancel, (d, w) -> d.dismiss())
+ .show();
+ return true;
+ }
+
+ void refresh() {
+ List<HistoryItem> items = mDbHandler.getAllItems();
+ // Reverse database list order
+ Collections.reverse(items);
+ mAdapter.updateList(items);
+
+ if (items.isEmpty()) {
+ mList.setVisibility(View.GONE);
+ mEmptyView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void deleteAll() {
+ ProgressDialog dialog = new ProgressDialog(this);
+ dialog.setTitle(getString(R.string.history_delete_title));
+ dialog.setMessage(getString(R.string.history_deleting_message));
+ dialog.setCancelable(false);
+ dialog.setIndeterminate(true);
+ dialog.show();
+
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(Void... params) {
+ mDbHandler.deleteAll();
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean param) {
+ new Handler().postDelayed(() -> {
+ dialog.dismiss();
+ refresh();
+ }, 1000);
+ }
+ }.execute();
+ }
+
+ HistoryAdapter getAdapter() {
+ return mAdapter;
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/history/HistoryAdapter.java b/app/src/main/java/org/lineageos/jelly/history/HistoryAdapter.java
new file mode 100644
index 0000000..cf11923
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/history/HistoryAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.history;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import org.lineageos.jelly.R;
+
+import java.util.List;
+
+class HistoryAdapter extends RecyclerView.Adapter<HistoryHolder> {
+
+ private final Context mContext;
+ private List<HistoryItem> mList;
+
+ HistoryAdapter(Context context, List<HistoryItem> list) {
+ mContext = context;
+ mList = list;
+ }
+
+ @Override
+ public HistoryHolder onCreateViewHolder(ViewGroup parent, int type) {
+ return new HistoryHolder(LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.item_history, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(HistoryHolder holder, int position) {
+ holder.setData(mContext, mList.get(position));
+ }
+
+ @Override
+ public int getItemCount() {
+ return mList.size();
+ }
+
+ void updateList(List<HistoryItem> list) {
+ mList = list;
+ notifyDataSetChanged();
+ }
+
+ void removeItem(long id) {
+ int position = 0;
+ for (; position < mList.size(); position++) {
+ if (mList.get(position).getId() == id) {
+ break;
+ }
+ }
+
+ if (position == mList.size()) {
+ return;
+ }
+
+ mList.remove(position);
+ notifyItemRemoved(position);
+
+ if (mList.isEmpty()) {
+ // Show empty status
+ ((HistoryActivity) mContext).refresh();
+ }
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/history/HistoryDatabaseHandler.java b/app/src/main/java/org/lineageos/jelly/history/HistoryDatabaseHandler.java
new file mode 100644
index 0000000..6b977cf
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/history/HistoryDatabaseHandler.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.history;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class HistoryDatabaseHandler extends SQLiteOpenHelper {
+
+ private static final int DB_VERSION = 1;
+ private static final String DB_NAME = "HistoryDatabase";
+ private static final String DB_TABLE_HISTORY = "history";
+ private static final String KEY_ID = "id";
+ private static final String KEY_TITLE = "title";
+ private static final String KEY_URL = "url";
+
+
+ public HistoryDatabaseHandler(Context context) {
+ super(context, DB_NAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + DB_TABLE_HISTORY + " (" +
+ KEY_ID + " INTEGER PRIMARY KEY, " +
+ KEY_TITLE + " TEXT, " +
+ KEY_URL + " TEXT)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // Update this when db table will be changed
+ }
+
+ public void addItem(HistoryItem item) {
+ if (item.getId() == -1) {
+ item.setId(System.currentTimeMillis());
+ }
+
+ ContentValues values = new ContentValues();
+ values.put(KEY_ID, item.getId());
+ values.put(KEY_TITLE, item.getTitle());
+ values.put(KEY_URL, item.getUrl());
+
+ SQLiteDatabase db = getWritableDatabase();
+ db.insert(DB_TABLE_HISTORY, null, values);
+ db.close();
+ }
+
+ void deleteItem(long id) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.delete(DB_TABLE_HISTORY, KEY_ID + "=?", new String[]{String.valueOf(id)});
+ db.close();
+ }
+
+ List<HistoryItem> getAllItems() {
+ List<HistoryItem> list = new ArrayList<>();
+ SQLiteDatabase db = getWritableDatabase();
+ Cursor cursor = db.rawQuery("SELECT * FROM " + DB_TABLE_HISTORY, null);
+
+ if (cursor.moveToFirst()) {
+ do {
+ list.add(new HistoryItem(Long.parseLong(cursor.getString(0)),
+ cursor.getString(1), cursor.getString(2)));
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ db.close();
+ return list;
+ }
+
+ void deleteAll() {
+ SQLiteDatabase db = getWritableDatabase();
+ db.delete(DB_TABLE_HISTORY, KEY_ID + ">=?", new String[]{"0"});
+ db.close();
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/history/HistoryHolder.java b/app/src/main/java/org/lineageos/jelly/history/HistoryHolder.java
new file mode 100644
index 0000000..12887d9
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/history/HistoryHolder.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.history;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.lineageos.jelly.MainActivity;
+import org.lineageos.jelly.R;
+import org.lineageos.jelly.utils.UiUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+class HistoryHolder extends RecyclerView.ViewHolder {
+
+ private final LinearLayout mRootLayout;
+ private final TextView mTitle;
+ private final TextView mSummary;
+
+ HistoryHolder(View view) {
+ super(view);
+ mRootLayout = (LinearLayout) view.findViewById(R.id.row_history_layout);
+ mTitle = (TextView) view.findViewById(R.id.row_history_title);
+ mSummary = (TextView) view.findViewById(R.id.row_history_summary);
+ }
+
+ void setData(Context context, HistoryItem item) {
+ String title = item.getTitle();
+ if (title == null || title.isEmpty()) {
+ title = item.getUrl().split("/")[2];
+ }
+ mTitle.setText(title);
+ mSummary.setText(new SimpleDateFormat(context.getString(R.string.history_date_format),
+ Locale.getDefault()).format(new Date(item.getId())));
+
+ mRootLayout.setOnClickListener(v -> {
+ Intent intent = new Intent(context, MainActivity.class);
+ intent.setData(Uri.parse(item.getUrl()));
+ context.startActivity(intent);
+ });
+
+ mRootLayout.setOnLongClickListener(v -> {
+ new HistoryDatabaseHandler(context).deleteItem(item.getId());
+ ((HistoryActivity) context).getAdapter().removeItem(item.getId());
+ return true;
+ });
+
+ int background;
+ switch (UiUtils.getPositionInTime(item.getId())) {
+ case 0:
+ background = R.color.history_last_hour;
+ break;
+ case 1:
+ background = R.color.history_today;
+ break;
+ case 2:
+ background = R.color.history_this_week;
+ break;
+ case 3:
+ background = R.color.history_this_month;
+ break;
+ default:
+ background = R.color.history_earlier;
+ break;
+ }
+ mRootLayout.setBackgroundColor(ContextCompat.getColor(context, background));
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/history/HistoryItem.java b/app/src/main/java/org/lineageos/jelly/history/HistoryItem.java
new file mode 100644
index 0000000..d8fbded
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/history/HistoryItem.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.history;
+
+public class HistoryItem {
+
+ private final String title;
+ private final String url;
+ private long id = -1;
+
+ public HistoryItem(String title, String url) {
+ this.title = title;
+ this.url = url;
+ }
+
+ HistoryItem(long id, String title, String url) {
+ this.id = id;
+ this.title = title;
+ this.url = url;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public void setId(long id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ String getUrl() {
+ return url;
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/ui/EditTextExt.java b/app/src/main/java/org/lineageos/jelly/ui/EditTextExt.java
new file mode 100644
index 0000000..3074f9f
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/ui/EditTextExt.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.ui;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Shader;
+import android.support.v7.widget.AppCompatEditText;
+import android.util.AttributeSet;
+
+public class EditTextExt extends AppCompatEditText {
+
+ private int mPositionX;
+
+ public EditTextExt(Context context) {
+ super(context);
+ }
+
+ public EditTextExt(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public EditTextExt(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ private static LinearGradient getGradient(float widthEnd, float fadeStart,
+ float stopStart, float stopEnd, int color) {
+ return new LinearGradient(0, 0, widthEnd, 0,
+ new int[] { color, Color.TRANSPARENT, color, color, Color.TRANSPARENT },
+ new float[] { 0, fadeStart, stopStart, stopEnd, 1f }, Shader.TileMode.CLAMP);
+ }
+
+ @Override
+ protected void onScrollChanged(int x, int y, int oldX, int oldY) {
+ super.onScrollChanged(x, y, oldX, oldY);
+ mPositionX = x;
+ requestLayout();
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ float lineWidth = getLayout().getLineWidth(0);
+ float width = getMeasuredWidth();
+
+ if (getText() == null || getText().length() == 0 || lineWidth <= width) {
+ super.onDraw(canvas);
+ getPaint().setShader(null);
+ return;
+ }
+
+ int textColor = getCurrentTextColor();
+ float widthEnd = width + mPositionX;
+ float percent = (int) (width * 0.2);
+
+ float fadeStart = mPositionX / widthEnd;
+
+ float stopStart = mPositionX > 0 ? ((mPositionX + percent) / widthEnd) : 0;
+ float stopEnd = (widthEnd - (lineWidth > widthEnd ? percent : 0)) / widthEnd;
+ getPaint().setShader(getGradient(widthEnd, fadeStart, stopStart, stopEnd, textColor));
+ super.onDraw(canvas);
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/utils/PrefsUtils.java b/app/src/main/java/org/lineageos/jelly/utils/PrefsUtils.java
new file mode 100644
index 0000000..47bb137
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/utils/PrefsUtils.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import org.lineageos.jelly.R;
+
+public final class PrefsUtils {
+ private static final String KEY_SEARCH_ENGINE = "key_search_engine";
+ private static final String KEY_HOME_PAGE = "key_home_page";
+ private static final String KEY_ADVANCED_SHARE = "key_advanced_share";
+ private static final String KEY_LOOKLOCK = "key_looklock";
+ private static final String KEY_JS = "key_javascript";
+ private static final String KEY_LOCATION = "key_location";
+ private static final String KEY_COOKIE = "key_cookie";
+
+ private PrefsUtils() {
+ }
+
+ public static String getSearchEngine(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getString(KEY_SEARCH_ENGINE,
+ context.getString(R.string.default_search_engine));
+ }
+
+ public static String getHomePage(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getString(KEY_HOME_PAGE, context.getString(R.string.default_home_page));
+ }
+
+ public static boolean getAdvancedShare(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean(KEY_ADVANCED_SHARE, false);
+ }
+
+ public static boolean getLookLock(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean(KEY_LOOKLOCK, false);
+ }
+
+ public static boolean getJavascript(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean(KEY_JS, true);
+ }
+
+ public static boolean getLocation(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean(KEY_LOCATION, true);
+ }
+
+ public static boolean getCookie(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ return prefs.getBoolean(KEY_COOKIE, true);
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/utils/UiUtils.java b/app/src/main/java/org/lineageos/jelly/utils/UiUtils.java
new file mode 100644
index 0000000..9fa5f0a
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/utils/UiUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.utils;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.graphics.ColorUtils;
+import android.support.v7.graphics.Palette;
+import android.util.TypedValue;
+
+import org.lineageos.jelly.R;
+
+public final class UiUtils {
+
+ private UiUtils() {
+ }
+
+ public static boolean isColorLight(int color) {
+ int red = Color.red(color);
+ int green = Color.green(color);
+ int blue = Color.blue(color);
+
+ float hsl[] = new float[3];
+ ColorUtils.RGBToHSL(red, green, blue, hsl);
+ return hsl[2] > 0.5f;
+ }
+
+ public static int getColor(Context context, Bitmap bitmap, boolean incognito) {
+ Palette palette = Palette.from(bitmap).generate();
+ int primary = ContextCompat.getColor(context, R.color.colorPrimary);
+ int alternative = ContextCompat.getColor(context, R.color.colorIncognito);
+ return incognito ?
+ palette.getMutedColor(alternative) : palette.getVibrantColor(primary);
+ }
+
+ public static Bitmap getShortcutIcon(Context context, Bitmap bitmap) {
+ Bitmap out = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getWidth(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(out);
+ int color = getColor(context, bitmap, false);
+ Paint paint = new Paint();
+ Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getWidth());
+ float radius = bitmap.getWidth() / 2;
+ paint.setAntiAlias(true);
+ paint.setColor(color);
+ canvas.drawARGB(0, 0, 0, 0);
+ canvas.drawCircle(radius, radius, radius, paint);
+ paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+ canvas.drawBitmap(bitmap, rect, rect, paint);
+ return Bitmap.createScaledBitmap(out, 192, 192, true);
+ }
+
+ public static int getPositionInTime(long timeMilliSec) {
+ long diff = System.currentTimeMillis() - timeMilliSec;
+
+ long hour = 1000 * 60 * 60;
+ long day = hour * 24;
+ long week = day * 7;
+ long month = day * 30;
+
+ return hour > diff ? 0 : day > diff ? 1 : week > diff ? 2 : month > diff ? 3 : 4;
+ }
+
+ public static float dpToPx(Resources res, int dp) {
+ return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics());
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/utils/UrlUtils.java b/app/src/main/java/org/lineageos/jelly/utils/UrlUtils.java
new file mode 100644
index 0000000..350a5ac
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/utils/UrlUtils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.utils;
+
+import android.util.Log;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.regex.Pattern;
+
+public final class UrlUtils {
+ public static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile(
+ "(?i)" + // switch on case insensitive matching
+ "(" + // begin group for schema
+ "(?:http|https|file|chrome):\\/\\/" +
+ "|(?:inline|data|about|javascript):" +
+ ")" +
+ "(.*)"
+ );
+ private static final String TAG = UrlUtils.class.getSimpleName();
+
+ private UrlUtils() {
+ }
+
+ public static String fixUrl(String inUrl) {
+ inUrl = inUrl.toLowerCase();
+ int colon = inUrl.indexOf(':');
+ boolean allLower = true;
+ for (int index = 0; index < colon; index++) {
+ char ch = inUrl.charAt(index);
+ if (!Character.isLetter(ch)) {
+ break;
+ }
+ allLower &= Character.isLowerCase(ch);
+ if (index == colon - 1 && !allLower) {
+ inUrl = inUrl.substring(0, colon).toLowerCase()
+ + inUrl.substring(colon);
+ }
+ }
+ if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
+ return inUrl;
+ if (inUrl.startsWith("http:") ||
+ inUrl.startsWith("https:")) {
+ if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) {
+ inUrl = inUrl.replaceFirst("/", "//");
+ } else inUrl = inUrl.replaceFirst(":", "://");
+ }
+ return inUrl;
+ }
+
+ /**
+ * Formats a launch-able uri out of the template uri by replacing the template parameters with
+ * actual values.
+ */
+ public static String getFormattedUri(String templateUri, String query) {
+ if (templateUri.isEmpty()) {
+ return null;
+ }
+
+ // Encode the query terms in the UTF-8 encoding
+ try {
+ return templateUri.replace("{searchTerms}", URLEncoder.encode(query, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ Log.e(TAG, "Exception occurred when encoding query " + query + " to UTF-8");
+ return null;
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/org/lineageos/jelly/webview/ChromeClient.java b/app/src/main/java/org/lineageos/jelly/webview/ChromeClient.java
new file mode 100644
index 0000000..1f7c576
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/webview/ChromeClient.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.webview;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.view.View;
+import android.webkit.GeolocationPermissions;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebView;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+import android.widget.Toast;
+
+import org.lineageos.jelly.MainActivity;
+import org.lineageos.jelly.R;
+import org.lineageos.jelly.history.HistoryDatabaseHandler;
+import org.lineageos.jelly.history.HistoryItem;
+
+
+class ChromeClient extends WebChromeClient {
+
+ private final Context mContext;
+ private final HistoryDatabaseHandler mHistoryHandler;
+ private final boolean mIncognito;
+
+ private EditText mEditText;
+ private ProgressBar mProgressBar;
+
+ ChromeClient(Context context, boolean incognito) {
+ super();
+ mContext = context;
+ mHistoryHandler = new HistoryDatabaseHandler(context);
+ mIncognito = incognito;
+ }
+
+ @Override
+ public void onProgressChanged(WebView view, int progress) {
+ mProgressBar.setVisibility(progress == 100 ? View.INVISIBLE : View.VISIBLE);
+ mProgressBar.setProgress(progress == 100 ? 0 : progress);
+ super.onProgressChanged(view, progress);
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ mEditText.setText(view.getUrl());
+ mHistoryHandler.addItem(new HistoryItem(title, view.getUrl()));
+ }
+
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ ((MainActivity) mContext).setColor(icon, mIncognito);
+ }
+
+ @Override
+ public boolean onShowFileChooser(WebView view, ValueCallback<Uri[]> path,
+ FileChooserParams params) {
+ Intent intent = params.createIntent();
+ try {
+ ((MainActivity) mContext).startActivityForResult(intent, MainActivity.FILE_CHOOSER_REQ);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(mContext, mContext.getString(R.string.error_no_activity_found),
+ Toast.LENGTH_LONG).show();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ MainActivity activity = ((MainActivity) mContext);
+ if (activity.hasLocationPermission()) {
+ activity.requestLocationPermission();
+ } else {
+ callback.invoke(origin, true, false);
+ }
+ }
+
+ void bindEditText(EditText editText) {
+ mEditText = editText;
+ }
+
+ void bindProgressBar(ProgressBar progressBar) {
+ mProgressBar = progressBar;
+ }
+}
diff --git a/app/src/main/java/org/lineageos/jelly/webview/WebClient.java b/app/src/main/java/org/lineageos/jelly/webview/WebClient.java
new file mode 100644
index 0000000..43230ab
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/webview/WebClient.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.webview;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.support.design.widget.Snackbar;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import org.lineageos.jelly.R;
+
+class WebClient extends WebViewClient {
+
+ WebClient() {
+ super();
+ }
+
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+ String url = request.getUrl().toString();
+ Context context = view.getContext();
+ if (!url.startsWith("http")) {
+ try {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(request.getUrl());
+ context.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Snackbar.make(view, context.getString(R.string.error_no_activity_found),
+ Snackbar.LENGTH_LONG).show();
+ }
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/app/src/main/java/org/lineageos/jelly/webview/WebViewExt.java b/app/src/main/java/org/lineageos/jelly/webview/WebViewExt.java
new file mode 100644
index 0000000..ec09df9
--- /dev/null
+++ b/app/src/main/java/org/lineageos/jelly/webview/WebViewExt.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2017 The LineageOS Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.lineageos.jelly.webview;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Patterns;
+import android.view.View;
+import android.webkit.URLUtil;
+import android.webkit.WebView;
+import android.widget.EditText;
+import android.widget.ProgressBar;
+
+import org.lineageos.jelly.MainActivity;
+import org.lineageos.jelly.utils.PrefsUtils;
+import org.lineageos.jelly.utils.UrlUtils;
+
+public class WebViewExt extends WebView {
+
+ private final Context mContext;
+
+ public WebViewExt(Context context) {
+ super(context);
+ mContext = context;
+ setup();
+ }
+
+ public WebViewExt(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mContext = context;
+ setup();
+ }
+
+ public WebViewExt(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mContext = context;
+ setup();
+ }
+
+ @Override
+ public void loadUrl(String url) {
+ // Try to add http prefix
+ if (!url.startsWith("http")) {
+ String withHttp = "http://" + url;
+ if ((Patterns.WEB_URL.matcher(withHttp).matches() ||
+ UrlUtils.ACCEPTED_URI_SCHEMA.matcher(withHttp).matches()) &&
+ withHttp.contains(".")) {
+ super.loadUrl(withHttp);
+ return;
+ }
+ }
+
+ // http url
+ String query = UrlUtils.fixUrl(url).trim();
+ if (Patterns.WEB_URL.matcher(query).matches() ||
+ UrlUtils.ACCEPTED_URI_SCHEMA.matcher(query).matches() ||
+ query.isEmpty()) {
+ super.loadUrl(url);
+ return;
+ }
+
+ // Query
+ String baseUrl = PrefsUtils.getSearchEngine(mContext);
+ super.loadUrl(UrlUtils.getFormattedUri(baseUrl, query));
+ }
+
+ private void setup() {
+ getSettings().setJavaScriptEnabled(PrefsUtils.getJavascript(mContext));
+ getSettings().setGeolocationEnabled(PrefsUtils.getLocation(mContext));
+ getSettings().setBuiltInZoomControls(true);
+ getSettings().setDisplayZoomControls(false);
+
+ setWebViewClient(new WebClient());
+
+ setOnLongClickListener(new OnLongClickListener() {
+ boolean shouldAllowDownload;
+
+ @Override
+ public boolean onLongClick(View v) {
+ HitTestResult result = getHitTestResult();
+ switch (result.getType()) {
+ case HitTestResult.IMAGE_TYPE:
+ case HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
+ shouldAllowDownload = true;
+ case HitTestResult.SRC_ANCHOR_TYPE:
+ ((MainActivity) mContext).showSheetMenu(result.getExtra(),
+ shouldAllowDownload);
+ shouldAllowDownload = false;
+ return true;
+ }
+ return false;
+ }
+ });
+
+ setDownloadListener((url, userAgent, contentDescription, mimeType, contentLength) ->
+ ((MainActivity) mContext).downloadFileAsk(url,
+ URLUtil.guessFileName(url, contentDescription, mimeType)));
+ }
+
+ public void init(Context context, EditText editText,
+ ProgressBar progressBar, boolean incognito) {
+ ChromeClient chromeClient = new ChromeClient(context, incognito);
+ chromeClient.bindEditText(editText);
+ chromeClient.bindProgressBar(progressBar);
+ setWebChromeClient(chromeClient);
+ }
+
+ public Bitmap getSnap() {
+ measure(MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ setDrawingCacheEnabled(true);
+ buildDrawingCache();
+ int size = getMeasuredWidth() > getMeasuredHeight() ?
+ getMeasuredHeight() : getMeasuredWidth();
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ Paint paint = new Paint();
+ int height = bitmap.getHeight();
+ canvas.drawBitmap(bitmap, 0, height, paint);
+ draw(canvas);
+ return bitmap;
+ }
+
+}
diff --git a/app/src/main/res/drawable/empty_background.xml b/app/src/main/res/drawable/empty_background.xml
new file mode 100644
index 0000000..979810d
--- /dev/null
+++ b/app/src/main/res/drawable/empty_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="oval">
+
+ <solid android:color="@color/empty_background" />
+ <size
+ android:width="120dp"
+ android:height="120dp" />
+
+</shape>
diff --git a/app/src/main/res/drawable/ic_back.xml b/app/src/main/res/drawable/ic_back.xml
new file mode 100644
index 0000000..9a49b5c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_back.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..20fa211
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_download.xml b/app/src/main/res/drawable/ic_download.xml
new file mode 100644
index 0000000..ef4758f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_download.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_favorite.xml b/app/src/main/res/drawable/ic_favorite.xml
new file mode 100644
index 0000000..0c71c6c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_favorite.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_favorite_add.xml b/app/src/main/res/drawable/ic_favorite_add.xml
new file mode 100644
index 0000000..956f6db
--- /dev/null
+++ b/app/src/main/res/drawable/ic_favorite_add.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M 8,13 L 11,13 L 11,16 L 13,16 L 13,13 L 16,13 L 16,11 L 13,11 L 13,8 L 11,8 L 11,11 L 8,11 L 8,13 M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_history.xml b/app/src/main/res/drawable/ic_history.xml
new file mode 100644
index 0000000..2b4d8bc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_history.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_incognito.xml b/app/src/main/res/drawable/ic_incognito.xml
new file mode 100644
index 0000000..e489464
--- /dev/null
+++ b/app/src/main/res/drawable/ic_incognito.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M12,3C9.31,3 7.41,4.22 7.41,4.22L6,9H18L16.59,4.22C16.59,4.22 14.69,3 12,3M12,11C9.27,11 5.39,11.54 5.13,11.59C4.09,11.87 3.25,12.15 2.59,12.41C1.58,12.75 1,13 1,13H23C23,13 22.42,12.75 21.41,12.41C20.75,12.15 19.89,11.87 18.84,11.59C18.84,11.59 14.82,11 12,11M7.5,14A3.5,3.5 0 0,0 4,17.5A3.5,3.5 0 0,0 7.5,21A3.5,3.5 0 0,0 11,17.5C11,17.34 11,17.18 10.97,17.03C11.29,16.96 11.63,16.9 12,16.91C12.37,16.91 12.71,16.96 13.03,17.03C13,17.18 13,17.34 13,17.5A3.5,3.5 0 0,0 16.5,21A3.5,3.5 0 0,0 20,17.5A3.5,3.5 0 0,0 16.5,14C15.03,14 13.77,14.9 13.25,16.19C12.93,16.09 12.55,16 12,16C11.45,16 11.07,16.09 10.75,16.19C10.23,14.9 8.97,14 7.5,14M7.5,15A2.5,2.5 0 0,1 10,17.5A2.5,2.5 0 0,1 7.5,20A2.5,2.5 0 0,1 5,17.5A2.5,2.5 0 0,1 7.5,15M16.5,15A2.5,2.5 0 0,1 19,17.5A2.5,2.5 0 0,1 16.5,20A2.5,2.5 0 0,1 14,17.5A2.5,2.5 0 0,1 16.5,15Z" />
+</vector>
+
diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml
new file mode 100644
index 0000000..330ebbb
--- /dev/null
+++ b/app/src/main/res/drawable/ic_menu.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_new_tab.xml b/app/src/main/res/drawable/ic_new_tab.xml
new file mode 100644
index 0000000..c65ad97
--- /dev/null
+++ b/app/src/main/res/drawable/ic_new_tab.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_refresh.xml b/app/src/main/res/drawable/ic_refresh.xml
new file mode 100644
index 0000000..771eda2
--- /dev/null
+++ b/app/src/main/res/drawable/ic_refresh.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
new file mode 100644
index 0000000..2fe40e8
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98s-0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.12,-0.22 -0.39,-0.3 -0.61,-0.22l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.23,-0.09 -0.49,0 -0.61,0.22l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98s0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.12,0.22 0.39,0.3 0.61,0.22l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.23,0.09 0.49,0 0.61,-0.22l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM12,15.5c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml
new file mode 100644
index 0000000..ae96135
--- /dev/null
+++ b/app/src/main/res/drawable/ic_share.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
+</vector>
diff --git a/app/src/main/res/drawable/ic_shortcut.xml b/app/src/main/res/drawable/ic_shortcut.xml
new file mode 100644
index 0000000..96d6630
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shortcut.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="@color/menu_icon"
+ android:pathData="M16,8h-2v3h-3v2h3v3h2v-3h3v-2h-3zM2,12c0,-2.79 1.64,-5.2 4.01,-6.32L6.01,3.52C2.52,4.76 0,8.09 0,12s2.52,7.24 6.01,8.48v-2.16C3.64,17.2 2,14.79 2,12zM15,3c-4.96,0 -9,4.04 -9,9s4.04,9 9,9 9,-4.04 9,-9 -4.04,-9 -9,-9zM15,19c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7z"/>
+</vector>
diff --git a/app/src/main/res/layout/activity_favorites.xml b/app/src/main/res/layout/activity_favorites.xml
new file mode 100644
index 0000000..89e5104
--- /dev/null
+++ b/app/src/main/res/layout/activity_favorites.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?colorPrimary" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="?actionBarSize">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/favorite_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingEnd="12dp"
+ android:paddingStart="12dp"
+ android:scrollbars="vertical" />
+
+ <LinearLayout
+ android:id="@+id/favorite_empty_layout"
+ style="@style/AppTheme.EmptyLayout"
+ tools:ignore="UseCompoundDrawables">
+
+ <ImageView
+ style="@style/AppTheme.EmptyImage"
+ android:src="@drawable/ic_favorite"
+ android:tint="@color/empty_image" />
+
+ <TextView
+ style="@style/AppTheme.EmptyText"
+ android:text="@string/favorite_empty" />
+ </LinearLayout>
+ </RelativeLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_history.xml b/app/src/main/res/layout/activity_history.xml
new file mode 100644
index 0000000..6583337
--- /dev/null
+++ b/app/src/main/res/layout/activity_history.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?colorPrimary" />
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingTop="?actionBarSize">
+
+ <android.support.v7.widget.RecyclerView
+ android:id="@+id/history_list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scrollbars="vertical" />
+
+ <LinearLayout
+ android:id="@+id/history_empty_layout"
+ style="@style/AppTheme.EmptyLayout"
+ tools:ignore="UseCompoundDrawables">
+
+ <ImageView
+ style="@style/AppTheme.EmptyImage"
+ android:src="@drawable/ic_history"
+ android:tint="@color/empty_image" />
+
+ <TextView
+ style="@style/AppTheme.EmptyText"
+ android:text="@string/history_empty" />
+ </LinearLayout>
+ </RelativeLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..3db09c4
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/coordinator_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.design.widget.AppBarLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:theme="@style/AppTheme.AppBarOverlay">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ style="@style/AppTheme.ToolbarTheme"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimaryDark"
+ app:popupTheme="@style/AppTheme.PopupOverlay">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ProgressBar
+ android:id="@+id/load_progress"
+ style="@style/Widget.AppCompat.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="2dp"
+ android:layout_alignParentBottom="true"
+ android:max="100"
+ android:paddingTop="2dp"
+ android:progress="54" />
+
+ <include
+ layout="@layout/search_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_above="@id/load_progress" />
+
+ </RelativeLayout>
+ </android.support.v7.widget.Toolbar>
+ </android.support.design.widget.AppBarLayout>
+
+ <android.support.v4.widget.SwipeRefreshLayout
+ android:id="@+id/swipe_refresh"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="?actionBarSize">
+
+ <org.lineageos.jelly.webview.WebViewExt
+ android:id="@+id/web_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ </android.support.v4.widget.SwipeRefreshLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
new file mode 100644
index 0000000..e664677
--- /dev/null
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?colorPrimary" />
+
+ <fragment
+ android:name="org.lineageos.jelly.SettingsActivity$MyPreferenceFragment"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/toolbar"
+ android:tag="org.lineageos.jelly.SettingsActivity$MyPreferenceFragment" />
+</RelativeLayout>
diff --git a/app/src/main/res/layout/dialog_favorite_edit.xml b/app/src/main/res/layout/dialog_favorite_edit.xml
new file mode 100644
index 0000000..9a9dfea
--- /dev/null
+++ b/app/src/main/res/layout/dialog_favorite_edit.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:paddingBottom="8dp"
+ android:paddingEnd="24dp"
+ android:paddingStart="24dp"
+ android:paddingTop="16dp">
+
+ <android.support.design.widget.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="8dp">
+
+ <org.lineageos.jelly.ui.EditTextExt
+ android:id="@+id/favorite_edit_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/favorite_edit_title" />
+ </android.support.design.widget.TextInputLayout>
+
+ <android.support.design.widget.TextInputLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:errorTextAppearance="@string/favorite_edit_error">
+
+ <org.lineageos.jelly.ui.EditTextExt
+ android:id="@+id/favorite_edit_url"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="@string/favorite_edit_url"
+ android:inputType="textUri" />
+ </android.support.design.widget.TextInputLayout>
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/item_favorite.xml b/app/src/main/res/layout/item_favorite.xml
new file mode 100644
index 0000000..6e27d8b
--- /dev/null
+++ b/app/src/main/res/layout/item_favorite.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/row_favorite_card"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ android:foreground="?selectableItemBackground"
+ android:orientation="vertical"
+ app:contentPadding="8dp">
+
+ <TextView
+ android:id="@+id/row_favorite_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:ellipsize="end"
+ android:maxLines="2"
+ android:paddingBottom="12dp"
+ android:paddingTop="12dp"
+ android:textAlignment="center"
+ android:textSize="18sp" />
+
+</android.support.v7.widget.CardView>
diff --git a/app/src/main/res/layout/item_history.xml b/app/src/main/res/layout/item_history.xml
new file mode 100644
index 0000000..1a750aa
--- /dev/null
+++ b/app/src/main/res/layout/item_history.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/row_history_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:foreground="?selectableItemBackground"
+ android:gravity="center_vertical"
+ android:minHeight="60dp"
+ android:orientation="vertical"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp">
+
+ <TextView
+ android:id="@+id/row_history_title"
+ style="@android:style/TextAppearance.Medium"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="marquee"
+ android:maxLines="1" />
+
+ <TextView
+ android:id="@+id/row_history_summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/app/src/main/res/layout/search_bar.xml b/app/src/main/res/layout/search_bar.xml
new file mode 100644
index 0000000..cead495
--- /dev/null
+++ b/app/src/main/res/layout/search_bar.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:paddingBottom="4dp"
+ android:paddingEnd="16dp"
+ android:paddingStart="16dp"
+ android:paddingTop="4dp">
+
+ <!-- Dummy view to catch focus -->
+ <View
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ android:focusable="true"
+ android:focusableInTouchMode="true" />
+
+ <android.support.v7.widget.CardView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:cardBackgroundColor="@color/cardview_light_background"
+ app:cardElevation="4dp"
+ app:contentPadding="2dp">
+
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageButton
+ android:id="@+id/search_menu"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:adjustViewBounds="true"
+ android:background="?selectableItemBackgroundBorderless"
+ android:padding="8dp"
+ android:src="@drawable/ic_menu" />
+
+ <org.lineageos.jelly.ui.EditTextExt
+ android:id="@+id/url_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_toStartOf="@id/search_menu"
+ android:background="@null"
+ android:fadingEdge="vertical"
+ android:imeOptions="actionSearch"
+ android:inputType="textUri"
+ android:maxLines="1"
+ android:nextFocusLeft="@id/url_bar"
+ android:nextFocusUp="@id/url_bar"
+ android:paddingStart="4dp"
+ android:textColor="@android:color/black"
+ tools:ignore="RtlSymmetry" />
+ </RelativeLayout>
+ </android.support.v7.widget.CardView>
+</RelativeLayout>
diff --git a/app/src/main/res/layout/sheet_actions.xml b/app/src/main/res/layout/sheet_actions.xml
new file mode 100644
index 0000000..c0d41c4
--- /dev/null
+++ b/app/src/main/res/layout/sheet_actions.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="180dp"
+ android:orientation="vertical"
+ app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
+ tools:ignore="UseCompoundDrawables">
+
+ <LinearLayout
+ android:id="@+id/sheet_new_tab"
+ style="@style/AppTheme.BottomSheetLayout">
+
+ <ImageView
+ style="@style/AppTheme.BottomSheetIcon"
+ android:src="@drawable/ic_new_tab" />
+
+ <TextView
+ style="@style/AppTheme.BottomSheetText"
+ android:text="@string/menu_in_new_tab" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/sheet_share"
+ style="@style/AppTheme.BottomSheetLayout">
+
+ <ImageView
+ style="@style/AppTheme.BottomSheetIcon"
+ android:src="@drawable/ic_share" />
+
+ <TextView
+ style="@style/AppTheme.BottomSheetText"
+ android:text="@string/menu_share" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/sheet_favourite"
+ style="@style/AppTheme.BottomSheetLayout">
+
+ <ImageView
+ style="@style/AppTheme.BottomSheetIcon"
+ app:srcCompat="@drawable/ic_favorite_add" />
+
+ <TextView
+ style="@style/AppTheme.BottomSheetText"
+ android:text="@string/menu_fav_add" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/sheet_download"
+ style="@style/AppTheme.BottomSheetLayout"
+ android:visibility="gone">
+
+ <ImageView
+ style="@style/AppTheme.BottomSheetIcon"
+ app:srcCompat="@drawable/ic_download" />
+
+ <TextView
+ style="@style/AppTheme.BottomSheetText"
+ android:text="@string/menu_download" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/app/src/main/res/menu/menu_history.xml b/app/src/main/res/menu/menu_history.xml
new file mode 100644
index 0000000..890681c
--- /dev/null
+++ b/app/src/main/res/menu/menu_history.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/menu_history_delete"
+ android:icon="@drawable/ic_delete"
+ android:title="@string/history_delete_title"
+ app:showAsAction="ifRoom" />
+</menu>
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
new file mode 100644
index 0000000..4557a73
--- /dev/null
+++ b/app/src/main/res/menu/menu_main.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/menu_new"
+ android:icon="@drawable/ic_new_tab"
+ android:title="@string/menu_new_tab"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_incognito"
+ android:icon="@drawable/ic_incognito"
+ android:title="@string/menu_incognito"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_reload"
+ android:icon="@drawable/ic_refresh"
+ android:title="@string/menu_reload"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_add_favorite"
+ android:icon="@drawable/ic_favorite_add"
+ android:title="@string/menu_fav_add"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_share"
+ android:icon="@drawable/ic_share"
+ android:title="@string/menu_share"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_favorite"
+ android:icon="@drawable/ic_favorite"
+ android:title="@string/menu_favorites"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_history"
+ android:icon="@drawable/ic_history"
+ android:title="@string/menu_history"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_shortcut"
+ android:icon="@drawable/ic_shortcut"
+ android:title="@string/menu_shortcut"
+ app:showAsAction="never" />
+ <item
+ android:id="@+id/menu_settings"
+ android:icon="@drawable/ic_settings"
+ android:title="@string/menu_settings"
+ app:showAsAction="never" />
+</menu>
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..d9dfdb9
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..09e1444
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..a61cc67
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..66fd773
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a7e5479
--- /dev/null
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..5909177
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <color name="colorPrimary">#fafafa</color>
+ <color name="colorPrimaryDark">#E0E0E0</color>
+ <color name="colorAccent">#FF4081</color>
+
+ <color name="colorIncognito">#000b4d</color>
+
+ <color name="menu_icon">#333333</color>
+
+ <color name="empty_image">#b1b1b1</color>
+ <color name="empty_background">#efefef</color>
+ <color name="empty_text">@color/empty_image</color>
+
+ <color name="history_last_hour">#fafafa</color>
+ <color name="history_today">#f6f6f6</color>
+ <color name="history_this_week">#f0f0f0</color>
+ <color name="history_this_month">#eeeeee</color>
+ <color name="history_earlier">#e5e5e5</color>
+</resources>
diff --git a/app/src/main/res/values/search_engines.xml b/app/src/main/res/values/search_engines.xml
new file mode 100644
index 0000000..ee8a428
--- /dev/null
+++ b/app/src/main/res/values/search_engines.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+ <string-array name="pref_search_engine_entries" translatable="false">
+ <item>Baidu</item>
+ <item>Bing</item>
+ <item>DuckDuckGo</item>
+ <item>Google</item>
+ <item>Yahoo</item>
+ </string-array>
+
+ <string-array name="pref_search_engine_entryvalues" translatable="false">
+ <item>https://www.baidu.com/s?wd={searchTerms}</item>
+ <item>https://www.bing.com/search?q={searchTerms}</item>
+ <item>https://duckduckgo.com/?q={searchTerms}</item>
+ <item>https://encrypted.google.com/search?q={searchTerms}</item>
+ <item>https://search.yahoo.com/p={searchTerms}</item>
+ </string-array>
+</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..523055d
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">Browser</string>
+
+ <!-- Menu action: create new tab -->
+ <string name="menu_new_tab">New tab</string>
+ <!-- Menu action: create new incognito tab -->
+ <string name="menu_incognito">Incognito tab</string>
+ <!-- Menu action: reload current page -->
+ <string name="menu_reload">Reload</string>
+ <!-- Menu action: add current page to favorites -->
+ <string name="menu_fav_add">Add to favorites</string>
+ <!-- Menu action: share current page -->
+ <string name="menu_share">Share</string>
+ <!-- Menu action: show favorites list -->
+ <string name="menu_favorites">Favorites</string>
+ <!-- Menu action: show history list -->
+ <string name="menu_history">History</string>
+ <!-- Menu action: add shortcut of the current page to the launcher -->
+ <string name="menu_shortcut">Add shortcut</string>
+ <!-- Menu action: show settings -->
+ <string name="menu_settings">Settings</string>
+ <!-- Menu action: download selected file / image -->
+ <string name="menu_download">Download</string>
+ <!-- Menu action: open selected link in a new tab -->
+ <string name="menu_in_new_tab">Open in new tab</string>
+
+ <!-- Dialog action: dismiss -->
+ <string name="dismiss">Dismiss</string>
+
+ <!-- Download dialog: title -->
+ <string name="download_title">Download file</string>
+ <!-- Download dialog: message -->
+ <string name="download_message">Do you want to download %1$s to the sdcard?</string>
+ <!-- Download dialog: button that starts the download -->
+ <string name="download_positive">Download</string>
+
+ <!-- Permission error dialog: title -->
+ <string name="permission_error_title">Permission error</string>
+ <!-- Permission error dialog: message for denied storage access-->
+ <string name="permission_error_storage">Browser needs storage access to download files. Please grant it to save files from the web</string>
+ <!-- Permission error dialog: button that triggers permission request again -->
+ <string name="permission_error_ask_again">Ask again</string>
+ <!-- Permission error snackBar: the permission has been denied until user enables it in settings -->
+ <string name="permission_error_forever">Permission denied forever. Please grant it in settings</string>
+
+ <!-- Shortcut: the current webPage has been added to the launcher -->
+ <string name="shortcut_added">Added to the home screen</string>
+
+ <!-- Settings: title -->
+ <string name="settings_title">Settings</string>
+ <!-- Settings: search engine preference title -->
+ <string name="pref_search_engine">Search engine</string>
+ <!-- Settings: home page preference title -->
+ <string name="pref_start_page">Home page</string>
+ <!-- Settings: select home page dialog title -->
+ <string name="pref_start_page_dialog_title">Select home page</string>
+ <!-- Settings: select home page dialog message -->
+ <string name="pref_start_page_dialog_message">Write the home page url</string>
+ <!-- Settings: privacy and security category -->
+ <string name="pref_privacy_security">Privacy &amp; security</string>
+ <!-- Settings: lookLock title -->
+ <string name="pref_looklock_title">LookLock</string>
+ <!-- Settings: lookLock summary -->
+ <string name="pref_looklock_summary">Prevent other apps from reading Browser\'s content</string>
+ <!-- Settings: javascript preference title -->
+ <string name="pref_js_title">Javascript</string>
+ <!-- Settings: javascript preference summary -->
+ <string name="pref_js_summary">Enable javascript</string>
+ <!-- Settings: location preference title -->
+ <string name="pref_location_title">Location</string>
+ <!-- Settings: location preference summary. Note that this doesn't allow permission access to the websites, but just allows the possibility of requesting access to it -->
+ <string name="pref_location_summary">Allow websites to request access to your location</string>
+ <!-- Settings: cookie preference title -->
+ <string name="pref_cookie_title">Cookies</string>
+ <!-- Settings: cookie preference summary -->
+ <string name="pref_cookie_summary">Allow websites to save and load cookies</string>
+ <!-- Settings: advanced share preference title -->
+ <string name="pref_screenshot_snap_title">Advanced share</string>
+ <!-- Settings: advanced share preference summary -->
+ <string name="pref_screenshot_snap_summary">Share preview of the shared WebPage</string>
+
+ <!-- History: title -->
+ <string name="history_title">History</string>
+ <!-- History: empty status text -->
+ <string name="history_empty">There\'s nothing here, browse on the internet to see your history here</string>
+ <!-- History: date format for items. EEEE = day (Monday), MMMM = month (January), yyyy = year (1970), HH = hour (12), mm = minutes (30) -->
+ <string name="history_date_format">EEEE MMMM dd yyyy, HH:mm</string>
+ <!-- History: delete history dialog title -->
+ <string name="history_delete_title">Clear history</string>
+ <!-- History: delete history dialog warning message -->
+ <string name="history_delete_message">You\'re going to delete all the history, this action cannot be undone. Do you want to proceed?</string>
+ <!-- History: delete history dialog button that erases all the history -->
+ <string name="history_delete_positive">Clear</string>
+ <!-- History: delete history "working" dialog-->
+ <string name="history_deleting_message">Clearing history\u2026</string>
+
+ <!-- Favorite: title -->
+ <string name="favorite_title">Favorites</string>
+ <!-- Favorite: snackBar message shown when an url is added to favorites -->
+ <string name="favorite_added">Added to favorites</string>
+ <!-- Favorite: empty status text -->
+ <string name="favorite_empty">There\'s nothing here, add a favorite link to see it here</string>
+ <!-- Favorite: edit dialog title -->
+ <string name="favorite_edit_dialog_title">Edit favorite</string>
+ <!-- Favorite: edit dialog: title of the favorite -->
+ <string name="favorite_edit_title">Title</string>
+ <!-- Favorite: edit dialog: url of the favorite-->
+ <string name="favorite_edit_url">Url</string>
+ <!-- Favorite: edit dialog positive button that save changes -->
+ <string name="favorite_edit_positive">Edit</string>
+ <!-- Favorite: edit dialog button that deletes the selected favorite -->
+ <string name="favorite_edit_delete">Delete</string>
+ <!-- Favorite: edit dialog: invalid url error message -->
+ <string name="favorite_edit_error">Insert a valid url</string>
+
+ <!-- No activity found to open the given url error -->
+ <string name="error_no_activity_found">No app can handle this link</string>
+
+ <string translatable="false" name="default_search_engine">https://duckduckgo.com/?q={searchTerms}</string>
+ <string translatable="false" name="default_home_page">https://duckduckgo.com</string>
+</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..d7d63c3
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <item name="colorPrimary">@color/colorPrimary</item>
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
+ <item name="colorAccent">@color/colorAccent</item>
+ <item name="android:windowLightStatusBar">true</item>
+ </style>
+
+ <style name="AppTheme.NoActionBar">
+ <item name="windowActionBar">false</item>
+ <item name="windowNoTitle">true</item>
+ </style>
+
+ <style name="AppTheme.ToolbarTheme" parent="Widget.AppCompat.Toolbar">
+ <item name="contentInsetStart">0dp</item>
+ </style>
+
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
+
+ <style name="AppTheme.PopupMenuOverlapAnchor">
+ <item name="android:overlapAnchor">true</item>
+ <item name="android:dropDownVerticalOffset">0dp</item>
+ <item name="android:dropDownHorizontalOffset">0dp</item>
+ </style>
+
+ <style name="AppTheme.BottomSheetLayout">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">60dp</item>
+ <item name="android:clickable">true</item>
+ <item name="android:focusable">true</item>
+ <item name="android:foreground">?android:attr/selectableItemBackground</item>
+ <item name="android:orientation">horizontal</item>
+ <item name="android:padding">16dp</item>
+ </style>
+
+ <style name="AppTheme.BottomSheetIcon">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:contentDescription">@null</item>
+ <item name="android:tint">@color/menu_icon</item>
+ </style>
+
+ <style name="AppTheme.BottomSheetText">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">center</item>
+ <item name="android:layout_marginStart">16dp</item>
+ </style>
+
+ <style name="AppTheme.EmptyLayout">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:gravity">center</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:visibility">gone</item>
+ </style>
+
+ <style name="AppTheme.EmptyImage">
+ <item name="android:layout_width">120dp</item>
+ <item name="android:layout_height">120dp</item>
+ <item name="android:background">@drawable/empty_background</item>
+ <item name="android:padding">8dp</item>
+ <item name="android:scaleType">fitXY</item>
+ </style>
+
+ <style name="AppTheme.EmptyText">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingEnd">64dp</item>
+ <item name="android:paddingStart">64dp</item>
+ <item name="android:paddingTop">19dp</item>
+ <item name="android:textAlignment">center</item>
+ <item name="android:textColor">@color/empty_text</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+</resources>
diff --git a/app/src/main/res/xml/backup_descriptor.xml b/app/src/main/res/xml/backup_descriptor.xml
new file mode 100644
index 0000000..2084478
--- /dev/null
+++ b/app/src/main/res/xml/backup_descriptor.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<full-backup-content>
+ <!-- Shared preferences -->
+ <include
+ domain="sharedpref"
+ path="org.lineageos.jelly_preferences.xml" />
+
+ <!-- Databases -->
+ <include
+ domain="database"
+ path="HistoryDatabase" />
+ <include
+ domain="database"
+ path="FavoriteDatabase" />
+</full-backup-content>
diff --git a/app/src/main/res/xml/file_provider.xml b/app/src/main/res/xml/file_provider.xml
new file mode 100644
index 0000000..aa235e6
--- /dev/null
+++ b/app/src/main/res/xml/file_provider.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<paths>
+ <cache-path
+ name="all_dirs"
+ path="." />
+</paths>
diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml
new file mode 100644
index 0000000..9205098
--- /dev/null
+++ b/app/src/main/res/xml/settings.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2017 The LineageOS Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ListPreference
+ android:defaultValue="@string/default_search_engine"
+ android:entries="@array/pref_search_engine_entries"
+ android:entryValues="@array/pref_search_engine_entryvalues"
+ android:key="key_search_engine"
+ android:summary="%s"
+ android:title="@string/pref_search_engine" />
+
+ <EditTextPreference
+ android:defaultValue="@string/default_home_page"
+ android:dialogMessage="@string/pref_start_page_dialog_message"
+ android:dialogTitle="@string/pref_start_page_dialog_title"
+ android:key="key_home_page"
+ android:title="@string/pref_start_page" />
+
+ <SwitchPreference
+ android:defaultValue="0"
+ android:key="key_advanced_share"
+ android:summary="@string/pref_screenshot_snap_summary"
+ android:title="@string/pref_screenshot_snap_title" />
+
+ <PreferenceCategory android:title="@string/pref_privacy_security">
+
+ <SwitchPreference
+ android:defaultValue="0"
+ android:key="key_looklock"
+ android:summary="@string/pref_looklock_summary"
+ android:title="@string/pref_looklock_title" />
+
+ <SwitchPreference
+ android:defaultValue="1"
+ android:key="key_javascript"
+ android:summary="@string/pref_js_summary"
+ android:title="@string/pref_js_title" />
+
+ <SwitchPreference
+ android:defaultValue="1"
+ android:key="key_location"
+ android:summary="@string/pref_location_summary"
+ android:title="@string/pref_location_title" />
+
+ <SwitchPreference
+ android:defaultValue="1"
+ android:key="key_cookie"
+ android:summary="@string/pref_cookie_summary"
+ android:title="@string/pref_cookie_title" />
+ </PreferenceCategory>
+</PreferenceScreen>
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..1ea4bd0
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,23 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.0'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ jcenter()
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..aac7c9b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,17 @@
+# Project-wide Gradle settings.
+
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx1536m
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..13372ae
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..61f2322
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Fri Apr 14 16:24:15 CEST 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..9d82f78
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..aec9973
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e7b4def
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+include ':app'