From 76b38bebadda8456766a19f1865b2a9b493d1150 Mon Sep 17 00:00:00 2001
From: Gabriel Calero <gcalero1984@gmail.com>
Date: Tue, 12 Dec 2017 15:34:02 -0300
Subject: [PATCH] Make Interface run in Android

---
 android/app/CMakeLists.txt                    |  46 ++--
 android/app/build.gradle                      |   5 +-
 android/app/src/main/AndroidManifest.xml      |  39 ++-
 android/app/src/main/cpp/main.cpp             |   5 +-
 .../hifiinterface/InterfaceActivity.java      | 178 +++++++++++++
 .../hifiinterface/PermissionChecker.java      | 130 ++++++++++
 .../hifiinterface/WebViewActivity.java        | 242 ++++++++++++++++++
 .../main/res/drawable/ic_close_black_24dp.xml |   9 +
 .../src/main/res/layout/activity_web_view.xml |  34 +++
 .../app/src/main/res/menu/web_view_menu.xml   |  10 +
 android/app/src/main/res/values/dimens.xml    |  12 +
 android/app/src/main/res/values/strings.xml   |   7 +-
 android/app/src/main/res/values/styles.xml    |  12 +-
 cmake/macros/TargetOpenGL.cmake               |   5 +-
 interface/CMakeLists.txt                      |  59 ++---
 interface/src/Application.cpp                 |  28 +-
 .../AssetMappingsScriptingInterface.cpp       |  26 +-
 interface/src/scripting/LimitlessConnection.h |   4 +-
 interface/src/ui/Stats.cpp                    |   5 +-
 .../src/avatars-renderer/Avatar.cpp           |   4 +-
 .../display-plugins/OpenGLDisplayPlugin.cpp   |  12 +-
 libraries/entities-renderer/CMakeLists.txt    |   3 +-
 .../script-engine/src/ArrayBufferClass.h      |   1 +
 .../src/ConsoleScriptingInterface.cpp         |   1 +
 libraries/ui/src/ui/OffscreenQmlSurface.cpp   |   8 +-
 libraries/ui/src/ui/types/FileTypeProfile.cpp |   9 +-
 .../ui/types/FileTypeRequestInterceptor.cpp   |   2 +-
 .../HFTabletWebEngineRequestInterceptor.h     |  20 +-
 .../ui/src/ui/types/HFWebEngineProfile.cpp    |  12 +-
 .../types/HFWebEngineRequestInterceptor.cpp   |   2 +-
 libraries/ui/src/ui/types/RequestFilters.cpp  |   2 +-
 31 files changed, 831 insertions(+), 101 deletions(-)
 create mode 100644 android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
 create mode 100644 android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
 create mode 100644 android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java
 create mode 100644 android/app/src/main/res/drawable/ic_close_black_24dp.xml
 create mode 100644 android/app/src/main/res/layout/activity_web_view.xml
 create mode 100644 android/app/src/main/res/menu/web_view_menu.xml
 create mode 100644 android/app/src/main/res/values/dimens.xml

diff --git a/android/app/CMakeLists.txt b/android/app/CMakeLists.txt
index 4411b7b1bb..4260882018 100644
--- a/android/app/CMakeLists.txt
+++ b/android/app/CMakeLists.txt
@@ -1,26 +1,28 @@
 set(TARGET_NAME native-lib)
-setup_hifi_library(Gui Qml Quick)
-
-# Minimal dependencies for testing UI compositing
-#link_hifi_libraries(shared networking gl ui)
-
-link_hifi_libraries(
-    shared networking octree
-    script-engine recording trackers
-    gl ktx image gpu gpu-gles render render-utils
-    physics
-    audio audio-client
-    ui midi controllers pointers
-    model model-networking fbx animation
-    entities entities-renderer
-    avatars avatars-renderer
-    ui-plugins input-plugins
-    # display-plugins 
-    # auto-updater
-)
-
-
-target_link_libraries(native-lib android log m)
+setup_hifi_library()
+link_hifi_libraries(shared networking gl gpu gpu-gles image fbx render-utils physics entities octree)
 target_opengl()
 target_bullet()
 
+set(INTERFACE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../interface")
+add_subdirectory("${INTERFACE_DIR}" "libraries/interface")
+include_directories("${INTERFACE_DIR}/src")
+
+target_link_libraries(native-lib android log m interface)
+
+set(GVR_ROOT "${HIFI_ANDROID_PRECOMPILED}/gvr/gvr-android-sdk-1.101.0/")
+target_include_directories(native-lib PRIVATE  "${GVR_ROOT}/libraries/headers")
+target_link_libraries(native-lib "${GVR_ROOT}/libraries/libgvr.so")
+
+# finished libraries
+# core -> qt
+# networking -> openssl, tbb
+# fbx -> draco
+# physics -> bullet
+# entities-renderer -> polyvox
+
+# unfinished libraries
+# image -> nvtt (doesn't look good, but can be made optional)
+# script-engine -> quazip (probably not required for the android client)
+
+
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 066eb7da3d..343074047e 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,10 +1,13 @@
 apply plugin: 'com.android.application'
 
+ext.RELEASE_NUMBER = project.hasProperty('RELEASE_NUMBER') ? project.getProperty('RELEASE_NUMBER') : '0'
+ext.RELEASE_TYPE = project.hasProperty('RELEASE_TYPE') ? project.getProperty('RELEASE_TYPE') : 'DEV'
+ext.BUILD_BRANCH = project.hasProperty('BUILD_BRANCH') ? project.getProperty('BUILD_BRANCH') : ''
 
 android {
     compileSdkVersion 26
     defaultConfig {
-        applicationId "com.highfidelity.iface"
+        applicationId "io.highfidelity.hifiinterface"
         minSdkVersion 24
         targetSdkVersion 26
         versionCode 1
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 2160f7b591..8e3b89d605 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.highfidelity.gvrinterface">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.highfidelity.hifiinterface">
+
     <uses-sdk android:minSdkVersion="24" android:targetSdkVersion="26" />
     <uses-feature android:glEsVersion="0x00030002" android:required="true" />
     <uses-permission android:name="android.permission.VIBRATE"/>
@@ -19,18 +20,34 @@
         android:icon="@mipmap/ic_launcher"
         android:launchMode="singleTop"
         android:roundIcon="@mipmap/ic_launcher_round">
-
+        <activity android:name="io.highfidelity.hifiinterface.PermissionChecker">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <activity android:name="io.highfidelity.hifiinterface.WebViewActivity"
+            android:theme="@android:style/Theme.Material.Light.NoActionBar"/>
+        <!-- We don't want to show this on Daydream yet (we need to fix the turn-around problem on this screen)
+         <activity android:name="io.highfidelity.hifiinterface.GvrLoaderActivity">
+           <intent-filter>
+               <action android:name="android.intent.action.MAIN" />
+               <category android:name="com.google.intent.category.DAYDREAM"/>
+           </intent-filter>
+         </activity>
+        -->
         <activity
+            android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
             android:name=".InterfaceActivity"
             android:label="@string/app_name"
-            android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation"
-            android:launchMode="singleTop"
             android:screenOrientation="landscape"
-            android:resizeableActivity="false">
+            android:launchMode="singleTop"
+            android:enableVrMode="com.google.vr.vrcore/com.google.vr.vrcore.common.VrCoreListenerService"
+            >
 
             <intent-filter>
-               <action android:name="android.intent.action.MAIN" />
-               <category android:name="android.intent.category.LAUNCHER" />
+                <category android:name="com.google.intent.category.DAYDREAM"/>
+                <action android:name="android.intent.action.MAIN" />
             </intent-filter>
 
             <meta-data android:name="android.app.lib_name" android:value="native-lib"/>
@@ -43,4 +60,10 @@
             <meta-data android:name="android.app.extract_android_style" android:value="full"/>
         </activity>
     </application>
-</manifest>
\ No newline at end of file
+
+    <!-- Tell the system this app requires OpenGL ES 3.0. -->
+    <uses-feature android:glEsVersion="0x00030000" android:required="true" />
+    <uses-feature android:name="android.software.vr.mode" android:required="true"/>
+    <uses-feature android:name="android.hardware.vr.high_performance" android:required="true"/>
+
+</manifest>
diff --git a/android/app/src/main/cpp/main.cpp b/android/app/src/main/cpp/main.cpp
index b947323720..27d43e34aa 100644
--- a/android/app/src/main/cpp/main.cpp
+++ b/android/app/src/main/cpp/main.cpp
@@ -1,4 +1,6 @@
-#include <jni.h>
+/*
+ The main function in this file overrides the one in interface library
+ #include <jni.h>
 
 #include <android/log.h>
 #include <QtCore/QDebug>
@@ -151,3 +153,4 @@ int main(int argc, char* argv[])
     timer.start();
     return app.exec();
 }
+*/
\ No newline at end of file
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
new file mode 100644
index 0000000000..de3bcee88d
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/InterfaceActivity.java
@@ -0,0 +1,178 @@
+//
+//  InterfaceActivity.java
+//  android/app/src/main/java
+//
+//  Created by Stephen Birarda on 1/26/15.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+package io.highfidelity.hifiinterface;
+
+import android.content.Intent;
+import android.content.res.AssetManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.util.Log;
+import org.qtproject.qt5.android.bindings.QtActivity;
+
+/*import com.google.vr.cardboard.DisplaySynchronizer;
+import com.google.vr.cardboard.DisplayUtils;
+import com.google.vr.ndk.base.GvrApi;*/
+import android.graphics.Point;
+import android.content.res.Configuration;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.view.View;
+
+public class InterfaceActivity extends QtActivity {
+
+    //public static native void handleHifiURL(String hifiURLString);
+    private native long nativeOnCreate(InterfaceActivity instance, AssetManager assetManager);
+    //private native void nativeOnPause();
+    //private native void nativeOnResume();
+    //private native void nativeOnStop();
+    //private native void nativeOnStart();
+    //private native void saveRealScreenSize(int width, int height);
+    //private native void setAppVersion(String version);
+    private native long nativeOnExitVr();
+
+    private AssetManager assetManager;
+
+    private static boolean inVrMode;
+//    private GvrApi gvrApi;
+    // Opaque native pointer to the Application C++ object.
+    // This object is owned by the InterfaceActivity instance and passed to the native methods.
+    //private long nativeGvrApi;
+    
+    public void enterVr() {
+        //Log.d("[VR]", "Entering Vr mode (java)");
+        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+        inVrMode = true;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        
+        // Get the intent that started this activity in case we have a hifi:// URL to parse
+        Intent intent = getIntent();
+        if (intent.getAction() == Intent.ACTION_VIEW) {
+            Uri data = intent.getData();
+
+//            if (data.getScheme().equals("hifi")) {
+//                handleHifiURL(data.toString());
+//            }
+        }
+        
+/*        DisplaySynchronizer displaySynchronizer = new DisplaySynchronizer(this, DisplayUtils.getDefaultDisplay(this));
+        gvrApi = new GvrApi(this, displaySynchronizer);
+        */
+//        Log.d("GVR", "gvrApi.toString(): " + gvrApi.toString());
+
+        assetManager = getResources().getAssets();
+
+        //nativeGvrApi =
+            nativeOnCreate(this, assetManager /*, gvrApi.getNativeGvrContext()*/);
+
+        Point size = new Point();
+        getWindowManager().getDefaultDisplay().getRealSize(size);
+//        saveRealScreenSize(size.x, size.y);
+
+        try {
+            PackageInfo pInfo = this.getPackageManager().getPackageInfo(getPackageName(), 0);
+            String version = pInfo.versionName;
+//            setAppVersion(version);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e("GVR", "Error getting application version", e);
+        }
+
+        final View rootView = getWindow().getDecorView().findViewById(android.R.id.content);
+
+        // This is a workaround to hide the menu bar when the virtual keyboard is shown from Qt
+        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new android.view.ViewTreeObserver.OnGlobalLayoutListener() {
+            @Override
+            public void onGlobalLayout() {
+                int heightDiff = rootView.getRootView().getHeight() - rootView.getHeight();
+                if (getActionBar().isShowing()) {
+                    getActionBar().hide();
+                }
+            }
+        });
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        //nativeOnPause();
+        //gvrApi.pauseTracking();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+//        nativeOnStart();
+    }
+
+    @Override
+    protected void onStop() {
+        Log.d("[Background]","Calling nativeOnStop from InterfaceActivity");
+//        nativeOnStop();
+        super.onStop();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        //nativeOnResume();
+        //gvrApi.resumeTracking();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        // Checks the orientation of the screen
+        if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
+//            Log.d("[VR]", "Portrait, forcing landscape");
+            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+            if (inVrMode) {
+                inVrMode = false;
+//                Log.d("[VR]", "Starting VR exit");
+                nativeOnExitVr();                
+            } else {
+                Log.w("[VR]", "Portrait detected but not in VR mode. Should not happen");
+            }
+        }
+    }
+
+    public void openUrlInAndroidWebView(String urlString) {
+        Log.d("openUrl", "Received in open " + urlString);
+        Intent openUrlIntent = new Intent(this, WebViewActivity.class);
+        openUrlIntent.putExtra(WebViewActivity.WEB_VIEW_ACTIVITY_EXTRA_URL, urlString);
+        startActivity(openUrlIntent);
+    }
+
+    /**
+     * Called when view focus is changed
+     */
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        if (hasFocus) {
+            final int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+
+            getWindow().getDecorView().setSystemUiVisibility(uiOptions);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
new file mode 100644
index 0000000000..34b087ca25
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/PermissionChecker.java
@@ -0,0 +1,130 @@
+package io.highfidelity.hifiinterface;
+
+import android.Manifest;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.app.Activity;
+
+import android.content.DialogInterface;
+import android.app.AlertDialog;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import android.util.Log;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.List;
+
+public class PermissionChecker extends Activity {
+    private static final int REQUEST_PERMISSIONS = 20;
+
+    private static final boolean CHOOSE_AVATAR_ON_STARTUP = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (CHOOSE_AVATAR_ON_STARTUP) {
+            showMenu();
+        }
+        this.requestAppPermissions(new
+                String[]{
+                Manifest.permission.READ_EXTERNAL_STORAGE,
+                Manifest.permission.WRITE_EXTERNAL_STORAGE,
+                Manifest.permission.RECORD_AUDIO,
+                Manifest.permission.CAMERA}
+            ,2,REQUEST_PERMISSIONS);
+
+    }
+
+    public void requestAppPermissions(final String[] requestedPermissions,
+                                      final int stringId, final int requestCode) {
+        int permissionCheck = PackageManager.PERMISSION_GRANTED;
+        boolean shouldShowRequestPermissionRationale = false;
+        for (String permission : requestedPermissions) {
+            permissionCheck = permissionCheck + checkSelfPermission(permission);
+            shouldShowRequestPermissionRationale = shouldShowRequestPermissionRationale || shouldShowRequestPermissionRationale(permission);
+        }
+        if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
+            System.out.println("Permission was not granted. Ask for permissions");
+            if (shouldShowRequestPermissionRationale) {
+                requestPermissions(requestedPermissions, requestCode);
+            } else {
+                requestPermissions(requestedPermissions, requestCode);
+            }
+        } else {
+            System.out.println("Launching the other activity..");
+            launchActivityWithPermissions();
+        }
+    }
+
+    private void launchActivityWithPermissions(){
+        finish();
+        Intent i = new Intent(this, InterfaceActivity.class);
+        startActivity(i);
+        finish();
+    }
+
+    private void showMenu(){
+        final List<String> avatarOptions = Arrays.asList("\uD83D\uDC66\uD83C\uDFFB Cody","\uD83D\uDC66\uD83C\uDFFF Will","\uD83D\uDC68\uD83C\uDFFD Albert", "\uD83D\uDC7D Being of Light");
+        final String[] avatarPaths = {
+            "http://mpassets.highfidelity.com/8c859fca-4cbd-4e82-aad1-5f4cb0ca5d53-v1/cody.fst",
+            "http://mpassets.highfidelity.com/d029ae8d-2905-4eb7-ba46-4bd1b8cb9d73-v1/4618d52e711fbb34df442b414da767bb.fst",
+            "http://mpassets.highfidelity.com/1e57c395-612e-4acd-9561-e79dbda0bc49-v1/albert.fst" };
+
+          final String pathForJson = "/data/data/io.highfidelity.hifiinterface/files/.config/High Fidelity - dev/";
+        new AlertDialog.Builder(this)
+        .setTitle("Pick an avatar")
+        .setItems(avatarOptions.toArray(new CharSequence[avatarOptions.size()]),new DialogInterface.OnClickListener(){
+
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                if(which < avatarPaths.length ) {
+                    JSONObject obj = new JSONObject();
+                        try {
+                            obj.put("firstRun",false);
+                            obj.put("Avatar/fullAvatarURL", avatarPaths[which]);
+                            File directory = new File(pathForJson);
+
+                            if(!directory.exists()) directory.mkdirs();
+
+                            File file = new File(pathForJson + "Interface.json");
+                            Writer output = new BufferedWriter(new FileWriter(file));
+                            output.write(obj.toString().replace("\\",""));
+                            output.close();
+                            System.out.println("I Could write config file expect to see the selected avatar"+obj.toString().replace("\\",""));
+
+                        } catch (JSONException e) {
+                            System.out.println("JSONException something weired went wrong");
+                        } catch (IOException e) {
+                            System.out.println("Could not write file :(");
+                        }
+                } else {
+                    System.out.println("Default avatar selected...");
+                }
+                launchActivityWithPermissions();
+            }
+        }).show();
+    }
+
+    @Override
+    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
+        int permissionCheck = PackageManager.PERMISSION_GRANTED;
+        for (int permission : grantResults) {
+            permissionCheck = permissionCheck + permission;
+        }
+        if ((grantResults.length > 0) && permissionCheck == PackageManager.PERMISSION_GRANTED) {
+            launchActivityWithPermissions();
+        } else if (grantResults.length > 0) {
+            System.out.println("User has deliberately denied Permissions. Launching anyways");
+            launchActivityWithPermissions();
+        }
+    }
+
+
+}
diff --git a/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java b/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java
new file mode 100644
index 0000000000..4d706248d8
--- /dev/null
+++ b/android/app/src/main/java/io/highfidelity/hifiinterface/WebViewActivity.java
@@ -0,0 +1,242 @@
+//
+//  WebViewActivity.java
+//  interface/java
+//
+//  Created by Cristian Duarte and Gabriel Calero on 8/17/17.
+//  Copyright 2017 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+
+//package hifiinterface.highfidelity.io.mybrowserapplication;
+package io.highfidelity.hifiinterface;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebChromeClient;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.ProgressBar;
+import android.widget.Toast;
+import android.widget.Toolbar;
+import android.os.Looper;
+import java.lang.Thread;
+import java.lang.Runnable;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class WebViewActivity extends Activity {
+
+    public static final String WEB_VIEW_ACTIVITY_EXTRA_URL = "url";
+
+    private native void nativeProcessURL(String url);
+
+    private WebView myWebView;
+    private ProgressBar mProgressBar;
+    private ActionBar mActionBar;
+    private String mUrl;
+
+    enum SafenessLevel {
+        NOT_ANALYZED_YET(""),
+        NOT_SECURE(""),
+        SECURE("\uD83D\uDD12 "),
+        BAD_SECURE("\uD83D\uDD13 ");
+
+        String icon;
+        SafenessLevel(String icon) {
+            this.icon = icon;
+        }
+    }
+
+    private SafenessLevel safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_web_view);
+
+        setActionBar((Toolbar) findViewById(R.id.toolbar_actionbar));
+        mActionBar = getActionBar();
+        mActionBar.setDisplayHomeAsUpEnabled(true);
+
+        mProgressBar = (ProgressBar) findViewById(R.id.toolbarProgressBar);
+
+        mUrl = getIntent().getStringExtra(WEB_VIEW_ACTIVITY_EXTRA_URL);
+        myWebView = (WebView) findViewById(R.id.web_view);
+        myWebView.setWebViewClient(new HiFiWebViewClient());
+        myWebView.setWebChromeClient(new HiFiWebChromeClient());
+        WebSettings webSettings = myWebView.getSettings();
+        webSettings.setJavaScriptEnabled(true);
+        webSettings.setBuiltInZoomControls(true);
+        webSettings.setDisplayZoomControls(false);
+        myWebView.loadUrl(mUrl);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        // Check if the key event was the Back button and if there's history
+        if ((keyCode == KeyEvent.KEYCODE_BACK) && myWebView.canGoBack()) {
+            myWebView.goBack();
+            return true;
+        }
+        // If it wasn't the Back key or there's no web page history, bubble up to the default
+        // system behavior (probably exit the activity)
+        return super.onKeyDown(keyCode, event);
+    }
+
+    private void showSubtitleWithUrl(String url) {
+        try {
+            mActionBar.setSubtitle(safenessLevel.icon + new URL(url.toString()).getHost());
+        } catch (MalformedURLException e) {
+            Toast.makeText(WebViewActivity.this, "Error loading page: " + "bad url", Toast.LENGTH_LONG).show();
+            Log.e("openUrl", "bad url");
+        }
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.web_view_menu, menu);
+        return true;
+    }
+
+    private String intentUrlOrWebUrl() {
+        return myWebView==null || myWebView.getUrl()==null?mUrl:myWebView.getUrl();
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item){
+        switch (item.getItemId()) {
+            // Respond to the action bar's Up/Home/back button
+            case android.R.id.home:
+                finish();
+                break;
+            case R.id.action_browser:
+                Intent i = new Intent(Intent.ACTION_VIEW);
+                i.setData(Uri.parse(intentUrlOrWebUrl()));
+                startActivity(i);
+                return true;
+            case R.id.action_share:
+                Intent is = new Intent(Intent.ACTION_SEND);
+                is.setType("text/plain");
+                is.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.web_view_action_share_subject));
+                is.putExtra(Intent.EXTRA_TEXT, intentUrlOrWebUrl());
+                startActivity(Intent.createChooser(is, getString(R.string.web_view_action_share_chooser)));
+                return true;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    class HiFiWebViewClient extends WebViewClient {
+
+        @Override
+        public void onPageFinished(WebView view, String url) {
+            super.onPageFinished(view, url);
+            mProgressBar.setVisibility(View.GONE);
+            if (safenessLevel!=SafenessLevel.BAD_SECURE) {
+                if (url.startsWith("https:")) {
+                    safenessLevel=SafenessLevel.SECURE;
+                } else {
+                    safenessLevel=SafenessLevel.NOT_SECURE;
+                }
+            }
+            showSubtitleWithUrl(url);
+        }
+
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            super.onPageStarted(view, url, favicon);
+            safenessLevel = SafenessLevel.NOT_ANALYZED_YET;
+            mProgressBar.setVisibility(View.VISIBLE);
+            mProgressBar.setProgress(0);
+            showSubtitleWithUrl(url);
+        }
+
+        @Override
+        public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+            Toast.makeText(WebViewActivity.this, "Error loading page: " + error.getDescription(), Toast.LENGTH_LONG).show();
+            if (ERROR_FAILED_SSL_HANDSHAKE == error.getErrorCode()) {
+                safenessLevel = SafenessLevel.BAD_SECURE;
+            }
+        }
+
+        @Override
+        public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
+            Toast.makeText(WebViewActivity.this, "Network Error loading page: " + errorResponse.getReasonPhrase(), Toast.LENGTH_LONG).show();
+        }
+
+        @Override
+        public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
+            super.onReceivedSslError(view, handler, error);
+            Toast.makeText(WebViewActivity.this, "SSL error loading page: " + error.toString(), Toast.LENGTH_LONG).show();
+            safenessLevel = SafenessLevel.BAD_SECURE;
+        }
+
+        private boolean isFst(WebResourceRequest request) {
+            return isFst(request.getUrl().toString());
+        }
+
+        private boolean isFst(String url) {
+            return url.endsWith(".fst");
+        }
+
+        @Override
+        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+            // managing avatar selections
+            if (isFst(request)) {
+                final String url = request.getUrl().toString();
+                new Thread(new Runnable() {
+                    public void run() {
+                        nativeProcessURL(url);
+                    }
+                }).start(); // Avoid deadlock in Qt dialog
+                WebViewActivity.this.finish();
+                return true;
+            }
+            return super.shouldOverrideUrlLoading(view, request);
+        }
+
+        @Override
+        public void onLoadResource(WebView view, String url) {
+            if (isFst(url)) {
+                // processed separately
+            } else {
+                super.onLoadResource(view, url);
+            }
+        }
+    }
+
+    class HiFiWebChromeClient extends WebChromeClient {
+
+        @Override
+        public void onProgressChanged(WebView view, int newProgress) {
+            super.onProgressChanged(view, newProgress);
+            mProgressBar.setProgress(newProgress);
+        }
+
+        @Override
+        public void onReceivedTitle(WebView view, String title) {
+            super.onReceivedTitle(view, title);
+            mActionBar.setTitle(title);
+        }
+
+    }
+}
diff --git a/android/app/src/main/res/drawable/ic_close_black_24dp.xml b/android/app/src/main/res/drawable/ic_close_black_24dp.xml
new file mode 100644
index 0000000000..ede4b7108d
--- /dev/null
+++ b/android/app/src/main/res/drawable/ic_close_black_24dp.xml
@@ -0,0 +1,9 @@
+<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,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+</vector>
diff --git a/android/app/src/main/res/layout/activity_web_view.xml b/android/app/src/main/res/layout/activity_web_view.xml
new file mode 100644
index 0000000000..1e30b58676
--- /dev/null
+++ b/android/app/src/main/res/layout/activity_web_view.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Toolbar
+        android:id="@+id/toolbar_actionbar"
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:layout_alignParentTop="true"
+        style="@android:style/Widget.Material.ActionBar"
+        android:titleTextAppearance="@style/ActionBarTitleStyle"
+        android:subtitleTextAppearance="@style/ActionBarSubtitleStyle"
+        android:navigationIcon="@drawable/ic_close_black_24dp"
+        android:contentInsetStart="0dp"
+        android:contentInsetStartWithNavigation="0dp"
+        android:title="">
+    </Toolbar>
+
+    <WebView
+        android:id="@+id/web_view"
+        android:layout_below="@id/toolbar_actionbar"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+    <ProgressBar
+        android:id="@+id/toolbarProgressBar"
+        android:layout_below="@id/toolbar_actionbar"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="3dp"
+        android:indeterminate="false"
+        android:padding="0dp" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/android/app/src/main/res/menu/web_view_menu.xml b/android/app/src/main/res/menu/web_view_menu.xml
new file mode 100644
index 0000000000..074e1608c5
--- /dev/null
+++ b/android/app/src/main/res/menu/web_view_menu.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:id="@+id/action_share"
+        android:title="@string/web_view_action_share"
+        android:showAsAction="never"/>
+    <item android:id="@+id/action_browser"
+        android:title="@string/web_view_action_open_in_browser"
+        android:showAsAction="never"/>
+</menu>
\ No newline at end of file
diff --git a/android/app/src/main/res/values/dimens.xml b/android/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000000..a9ec657aa9
--- /dev/null
+++ b/android/app/src/main/res/values/dimens.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+
+    <!-- Hack to have a desired text size for both orientations (default portrait is too big) -->
+    <!-- Default text size for action bar title.-->
+    <dimen name="text_size_title_material_toolbar">14dp</dimen>
+    <!-- Default text size for action bar subtitle.-->
+    <dimen name="text_size_subtitle_material_toolbar">12dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 5d6a4c1b99..b8080fae0f 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -1,3 +1,8 @@
 <resources>
-    <string name="app_name">TestApp</string>
+    <string name="app_name" translatable="false">Interface</string>
+    <string name="web_view_action_open_in_browser" translatable="false">Open in browser</string>
+    <string name="web_view_action_share" translatable="false">Share link</string>
+    <string name="web_view_action_share_subject" translatable="false">Shared a link</string>
+    <string name="web_view_action_share_chooser" translatable="false">Share link</string>
+
 </resources>
diff --git a/android/app/src/main/res/values/styles.xml b/android/app/src/main/res/values/styles.xml
index 033324ac58..23fe67f029 100644
--- a/android/app/src/main/res/values/styles.xml
+++ b/android/app/src/main/res/values/styles.xml
@@ -11,5 +11,15 @@
         <!--item name="android:background">@color/white_opaque</item-->
     </style>
 
-    
+    <!-- Overriding text size so it's not so big in portrait -->
+    <style name="ActionBarTitleStyle"
+        parent="@android:style/TextAppearance.Material.Widget.ActionBar.Title">
+        <item name="android:textSize">@dimen/text_size_title_material_toolbar</item>
+    </style>
+    <style name="ActionBarSubtitleStyle"
+        parent="@android:style/TextAppearance.Material.Widget.ActionBar.Subtitle">
+        <item name="android:textSize">@dimen/text_size_subtitle_material_toolbar</item>
+    </style>
+
+
 </resources>
diff --git a/cmake/macros/TargetOpenGL.cmake b/cmake/macros/TargetOpenGL.cmake
index 6ad92259bb..b9de4e6253 100644
--- a/cmake/macros/TargetOpenGL.cmake
+++ b/cmake/macros/TargetOpenGL.cmake
@@ -11,7 +11,10 @@ macro(TARGET_OPENGL)
       find_library(OpenGL OpenGL)
       target_link_libraries(${TARGET_NAME} ${OpenGL})
     elseif(ANDROID)
-      target_link_libraries(${TARGET_NAME} GLESv3 EGL)
+      find_library(EGL EGL)
+      find_library(OpenGLES3 GLESv3)
+      list(APPEND IGNORE_COPY_LIBS ${OpenGLES3} ${OpenGLES2} ${EGL})
+      target_link_libraries(${TARGET_NAME} ${OpenGLES3} ${EGL})
     else()
       find_package(OpenGL REQUIRED)
       if (${OPENGL_INCLUDE_DIR})
diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt
index e6b3392aad..cba8ce5479 100644
--- a/interface/CMakeLists.txt
+++ b/interface/CMakeLists.txt
@@ -58,6 +58,14 @@ else ()
   list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
 endif ()
 
+if (ANDROID)
+  set(PLATFORM_QT_COMPONENTS AndroidExtras)
+#  set(PLATFORM_QT_LIBRARIES Qt5::AndroidExtras)
+else ()
+  set(PLATFORM_QT_COMPONENTS WebEngine WebEngineWidgets)
+  set(PLATFORM_QT_LIBRARIES Qt5::WebEngine Qt5::WebEngineWidgets)
+endif ()
+
 find_package(
   Qt5 COMPONENTS
   Gui Multimedia Network OpenGL Qml Quick Script Svg
@@ -93,21 +101,7 @@ endif()
 
 # setup the android parameters that will help us produce an APK
 if (ANDROID)
-  set(ANDROID_APK_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk-build")
-  set(ANDROID_APK_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/apk")
-
-  set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${ANDROID_APK_OUTPUT_DIR}/libs/${ANDROID_ABI}")
-
   set(ANDROID_SDK_ROOT $ENV{ANDROID_HOME})
-  set(ANDROID_APP_DISPLAY_NAME Interface)
-  set(ANDROID_API_LEVEL 19)
-  set(ANDROID_APK_PACKAGE io.highfidelity.interface)
-  set(ANDROID_ACTIVITY_NAME io.highfidelity.interface.InterfaceActivity)
-  set(ANDROID_APK_VERSION_NAME "0.1")
-  set(ANDROID_APK_VERSION_CODE 1)
-  set(ANDROID_APK_FULLSCREEN TRUE)
-  set(ANDROID_DEPLOY_QT_INSTALL "--install")
-
   set(BUILD_SHARED_LIBS ON)
 endif ()
 
@@ -203,6 +197,13 @@ if (WIN32)
   set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF")
 endif()
 
+if (NOT ANDROID)
+  set(NON_ANDROID_LIBRARIES gpu-gl)
+else()
+  set(ANDROID_LIBRARIES gpu-gles)
+endif ()
+
+
 # link required hifi libraries
 link_hifi_libraries(
   shared octree ktx gpu gl procedural model render
@@ -212,6 +213,8 @@ link_hifi_libraries(
   render-utils entities-renderer avatars-renderer ui auto-updater midi
   controllers plugins image trackers
   ui-plugins display-plugins input-plugins
+  ${ANDROID_LIBRARIES}  
+  ${NON_ANDROID_LIBRARIES}
   ${PLATFORM_GL_BACKEND}
 )
 
@@ -262,15 +265,21 @@ endforeach()
 # include headers for interface and InterfaceConfig.
 include_directories("${PROJECT_SOURCE_DIR}/src")
 
+if (ANDROID)
+  #set(ANDROID_PLATFORM_QT_LIBRARIES Qt5::WebView)
+else()
+  set(NON_ANDROID_PLATFORM_QT_LIBRARIES Qt5::WebEngine)  
+endif ()
+
 target_link_libraries(
   ${TARGET_NAME}
   Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
   Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
-  Qt5::WebChannel Qt5::WebEngine
-  ${PLATFORM_QT_LIBRARIES}
+  Qt5::WebChannel ${NON_ANDROID_PLATFORM_QT_LIBRARIES}
+  ${ANDROID_PLATFORM_QT_LIBRARIES}
 )
 
-if (UNIX)
+if (UNIX AND NOT ANDROID)
     if (CMAKE_SYSTEM_NAME MATCHES "Linux")
         # Linux
         target_link_libraries(${TARGET_NAME} pthread atomic)
@@ -278,7 +287,7 @@ if (UNIX)
         # OSX
         target_link_libraries(${TARGET_NAME} pthread)
     endif ()
-endif(UNIX)
+endif()
 
 # assume we are using a Qt build without bearer management
 add_definitions(-DQT_NO_BEARERMANAGEMENT)
@@ -363,20 +372,6 @@ if (WIN32)
     package_libraries_for_deployment()
 endif()
 
-if (ANDROID)
-  set(HIFI_URL_INTENT "<intent-filter>\
-    \n        <action android:name='android.intent.action.VIEW' />\
-    \n        <category android:name='android.intent.category.DEFAULT' />\
-    \n        <category android:name='android.intent.category.BROWSABLE' />\
-    \n        <data android:scheme='hifi' />\
-    \n      </intent-filter>"
-  )
-
-  set(ANDROID_EXTRA_ACTIVITY_XML "${HIFI_URL_INTENT}")
-
-  qt_create_apk()
-endif ()
-
 add_dependency_external_projects(GifCreator)
 find_package(GifCreator REQUIRED)
 target_include_directories(${TARGET_NAME} PUBLIC ${GIFCREATOR_INCLUDE_DIRS})
diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp
index 8e890b6e77..12c8bcfc7d 100644
--- a/interface/src/Application.cpp
+++ b/interface/src/Application.cpp
@@ -210,7 +210,9 @@
 #include "commerce/QmlCommerce.h"
 
 #include "webbrowser/WebBrowserSuggestionsEngine.h"
-
+#ifdef ANDROID
+#include <QtAndroidExtras/QAndroidJniObject>
+#endif
 // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
 // FIXME seems to be broken.
 #if defined(Q_OS_WIN)
@@ -232,6 +234,30 @@ extern "C" {
 }
 #endif
 
+#ifdef ANDROID
+extern "C" {
+ 
+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnCreate(JNIEnv* env, jobject obj, jobject instance, jobject asset_mgr) {
+    qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId();
+}
+
+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnPause(JNIEnv* env, jobject obj) {
+     qDebug() << "nativeOnPause";
+}
+
+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnResume(JNIEnv* env, jobject obj) {
+    qDebug() << "nativeOnResume";
+}
+
+
+
+JNIEXPORT void Java_io_highfidelity_hifiinterface_InterfaceActivity_nativeOnExitVr(JNIEnv* env, jobject obj) {
+    qDebug() << "nativeOnCreate On thread " << QThread::currentThreadId();
+}
+
+
+}
+#endif
 enum ApplicationEvent {
     // Execute a lambda function
     Lambda = QEvent::User + 1,
diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp
index a1b2a9ccfc..5c27de84c9 100644
--- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp
+++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp
@@ -37,7 +37,8 @@ AssetMappingsScriptingInterface::AssetMappingsScriptingInterface() {
 void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJSValue callback) {
     auto assetClient = DependencyManager::get<AssetClient>();
     auto request = assetClient->createSetMappingRequest(path, hash);
-
+#ifndef ANDROID
+// TODO: just to make android compile
     connect(request, &SetMappingRequest::finished, this, [this, callback](SetMappingRequest* request) mutable {
         if (callback.isCallable()) {
             QJSValueList args { request->getErrorString(), request->getPath() };
@@ -46,6 +47,7 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS
 
         request->deleteLater();
     });
+#endif
 
     request->start();
 }
@@ -53,7 +55,8 @@ void AssetMappingsScriptingInterface::setMapping(QString path, QString hash, QJS
 void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback) {
     auto assetClient = DependencyManager::get<AssetClient>();
     auto request = assetClient->createGetMappingRequest(path);
-
+#ifndef ANDROID
+// TODO: just to make android compile
     connect(request, &GetMappingRequest::finished, this, [this, callback](GetMappingRequest* request) mutable {
         auto hash = request->getHash();
 
@@ -64,6 +67,7 @@ void AssetMappingsScriptingInterface::getMapping(QString path, QJSValue callback
 
         request->deleteLater();
     });
+#endif
 
     request->start();
 }
@@ -140,7 +144,8 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping,
 void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue callback) {
     auto assetClient = DependencyManager::get<AssetClient>();
     auto request = assetClient->createDeleteMappingsRequest(paths);
-
+#ifndef ANDROID
+// TODO: just to make android compile
     connect(request, &DeleteMappingsRequest::finished, this, [this, callback](DeleteMappingsRequest* request) mutable {
         if (callback.isCallable()) {
             QJSValueList args { request->getErrorString() };
@@ -149,6 +154,7 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue
 
         request->deleteLater();
     });
+#endif
 
     request->start();
 }
@@ -156,7 +162,8 @@ void AssetMappingsScriptingInterface::deleteMappings(QStringList paths, QJSValue
 void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) {
     auto assetClient = DependencyManager::get<AssetClient>();
     auto request = assetClient->createGetAllMappingsRequest();
-
+#ifndef ANDROID
+// TODO: just to make android compile
     connect(request, &GetAllMappingsRequest::finished, this, [this, callback](GetAllMappingsRequest* request) mutable {
         auto mappings = request->getMappings();
         auto map = callback.engine()->newObject();
@@ -172,6 +179,7 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) {
 
         request->deleteLater();
     });
+#endif
 
     request->start();
 }
@@ -179,7 +187,8 @@ void AssetMappingsScriptingInterface::getAllMappings(QJSValue callback) {
 void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString newPath, QJSValue callback) {
     auto assetClient = DependencyManager::get<AssetClient>();
     auto request = assetClient->createRenameMappingRequest(oldPath, newPath);
-
+#ifndef ANDROID
+// TODO: just to make android compile
     connect(request, &RenameMappingRequest::finished, this, [this, callback](RenameMappingRequest* request) mutable {
         if (callback.isCallable()) {
             QJSValueList args{ request->getErrorString() };
@@ -188,14 +197,15 @@ void AssetMappingsScriptingInterface::renameMapping(QString oldPath, QString new
 
         request->deleteLater();
     });
-
+#endif
     request->start();
 }
 
 void AssetMappingsScriptingInterface::setBakingEnabled(QStringList paths, bool enabled, QJSValue callback) {
     auto assetClient = DependencyManager::get<AssetClient>();
     auto request = assetClient->createSetBakingEnabledRequest(paths, enabled);
-
+#ifndef ANDROID
+// TODO: just to make android compile
     connect(request, &SetBakingEnabledRequest::finished, this, [this, callback](SetBakingEnabledRequest* request) mutable {
         if (callback.isCallable()) {
             QJSValueList args{ request->getErrorString() };
@@ -204,7 +214,7 @@ void AssetMappingsScriptingInterface::setBakingEnabled(QStringList paths, bool e
 
         request->deleteLater();
     });
-
+#endif
     request->start();
 }
 
diff --git a/interface/src/scripting/LimitlessConnection.h b/interface/src/scripting/LimitlessConnection.h
index ee049aff8e..cdb64a8197 100644
--- a/interface/src/scripting/LimitlessConnection.h
+++ b/interface/src/scripting/LimitlessConnection.h
@@ -15,7 +15,9 @@
 #include <AudioClient.h>
 #include <QObject>
 #include <QFuture>
-
+#ifdef ANDROID
+#include <QTcpSocket>
+#endif
 class LimitlessConnection : public QObject {
     Q_OBJECT
 public:
diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp
index f991420fe8..2e15f11c3e 100644
--- a/interface/src/ui/Stats.cpp
+++ b/interface/src/ui/Stats.cpp
@@ -42,8 +42,9 @@ using namespace std;
 
 static Stats* INSTANCE{ nullptr };
 
+#ifndef ANDROID
 QString getTextureMemoryPressureModeString();
-
+#endif
 Stats* Stats::getInstance() {
     if (!INSTANCE) {
         Stats::registerType();
@@ -359,7 +360,9 @@ void Stats::updateStats(bool force) {
     STAT_UPDATE(gpuTextureResourceMemory, (int)BYTES_TO_MB(gpu::Context::getTextureResourceGPUMemSize()));
     STAT_UPDATE(gpuTextureResourcePopulatedMemory, (int)BYTES_TO_MB(gpu::Context::getTextureResourcePopulatedGPUMemSize()));
     STAT_UPDATE(gpuTextureExternalMemory, (int)BYTES_TO_MB(gpu::Context::getTextureExternalGPUMemSize()));
+#ifndef ANDROID
     STAT_UPDATE(gpuTextureMemoryPressureState, getTextureMemoryPressureModeString());
+#endif
     STAT_UPDATE(gpuFreeMemory, (int)BYTES_TO_MB(gpu::Context::getFreeGPUMemSize()));
     STAT_UPDATE(rectifiedTextureCount, (int)RECTIFIED_TEXTURE_COUNT.load());
     STAT_UPDATE(decimatedTextureCount, (int)DECIMATED_TEXTURE_COUNT.load());
diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
index c532e7659f..c41372ee55 100644
--- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
+++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp
@@ -117,7 +117,7 @@ Avatar::Avatar(QThread* thread) :
 }
 
 Avatar::~Avatar() {
-    auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
+	auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
     EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;
     if (entityTree) {
         entityTree->withWriteLock([&] {
@@ -1287,7 +1287,7 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) {
     const float MOVE_DISTANCE_THRESHOLD = 0.001f;
     _moving = glm::distance(oldPosition, getWorldPosition()) > MOVE_DISTANCE_THRESHOLD;
     if (_moving) {
-        addPhysicsFlags(Simulation::DIRTY_POSITION);
+		addPhysicsFlags(Simulation::DIRTY_POSITION);
     }
     if (_moving || _hasNewJointData) {
         locationChanged();
diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
index e646ba27f5..90a4e75669 100644
--- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
+++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp
@@ -891,10 +891,14 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
         GLuint fbo[2] {0, 0};
 
         // need mipmaps for blitting texture
-        glGenerateTextureMipmap(sourceTexture);
+#ifndef ANDROID
+		glGenerateTextureMipmap(sourceTexture);
+#endif
 
         // create 2 fbos (one for initial texture, second for scaled one)
-        glCreateFramebuffers(2, fbo);
+#ifndef ANDROID
+	glCreateFramebuffers(2, fbo);
+#endif
 
         // setup source fbo
         glBindFramebuffer(GL_FRAMEBUFFER, fbo[0]);
@@ -924,7 +928,9 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
         } else {
             newY = (target->height() - newHeight) / 2;
         }
-        glBlitNamedFramebuffer(fbo[0], fbo[1], 0, 0, texWidth, texHeight, newX, newY, newX + newWidth, newY + newHeight, GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT, GL_NEAREST);
+#ifndef ANDROID
+		glBlitNamedFramebuffer(fbo[0], fbo[1], 0, 0, texWidth, texHeight, newX, newY, newX + newWidth, newY + newHeight, GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT, GL_NEAREST);
+#endif
 
         // don't delete the textures!
         glDeleteFramebuffers(2, fbo);
diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt
index cf94ecc37c..0dd96ff7ab 100644
--- a/libraries/entities-renderer/CMakeLists.txt
+++ b/libraries/entities-renderer/CMakeLists.txt
@@ -15,4 +15,5 @@ include_hifi_library_headers(avatars)
 include_hifi_library_headers(controllers)
 
 target_bullet()
-target_polyvox()
\ No newline at end of file
+target_polyvox()
+
diff --git a/libraries/script-engine/src/ArrayBufferClass.h b/libraries/script-engine/src/ArrayBufferClass.h
index 69c2cc0799..d65693bece 100644
--- a/libraries/script-engine/src/ArrayBufferClass.h
+++ b/libraries/script-engine/src/ArrayBufferClass.h
@@ -19,6 +19,7 @@
 #include <QtScript/QScriptEngine>
 #include <QtScript/QScriptString>
 #include <QtScript/QScriptValue>
+#include <QDateTime>
 
 class ScriptEngine;
 
diff --git a/libraries/script-engine/src/ConsoleScriptingInterface.cpp b/libraries/script-engine/src/ConsoleScriptingInterface.cpp
index f3ceee63f7..1e0ca2e42f 100644
--- a/libraries/script-engine/src/ConsoleScriptingInterface.cpp
+++ b/libraries/script-engine/src/ConsoleScriptingInterface.cpp
@@ -17,6 +17,7 @@
 
 #include "ConsoleScriptingInterface.h"
 #include "ScriptEngine.h"
+#include <QDateTime>
 
 #define INDENTATION 4 // 1 Tab - 4 spaces
 const QString LINE_SEPARATOR = "\n    ";
diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp
index 902f91f9b8..aa64610930 100644
--- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp
+++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp
@@ -282,7 +282,7 @@ private:
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f);
-#if !defined(Q_OS_ANDROID)
+#ifndef ANDROID
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.2f);
 #endif
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f);
@@ -450,7 +450,7 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) {
     if (!javaScriptToInject.isEmpty()) {
         rootContext->setContextProperty("eventBridgeJavaScriptToInject", QVariant(javaScriptToInject));
     }
-#if !defined(Q_OS_ANDROID)
+#ifndef ANDROID
     rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
     rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
 #endif
@@ -554,7 +554,9 @@ void OffscreenQmlSurface::render() {
 
     GLuint texture = offscreenTextures.getNextTexture(_size);
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
-    glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
+#ifndef ANDROID
+	glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0);
+#endif
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     _renderControl->render();
     glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
diff --git a/libraries/ui/src/ui/types/FileTypeProfile.cpp b/libraries/ui/src/ui/types/FileTypeProfile.cpp
index 90a2c6ba18..d31f09a981 100644
--- a/libraries/ui/src/ui/types/FileTypeProfile.cpp
+++ b/libraries/ui/src/ui/types/FileTypeProfile.cpp
@@ -16,13 +16,18 @@
 #if !defined(Q_OS_ANDROID)
 static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
 
-FileTypeProfile::FileTypeProfile(QObject* parent) :
-    QQuickWebEngineProfile(parent)
+FileTypeProfile::FileTypeProfile(QObject* parent) 
+#ifndef ANDROID
+	: QQuickWebEngineProfile(parent)
+#endif
 {
     static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
+#ifndef ANDROID
     setHttpUserAgent(WEB_ENGINE_USER_AGENT);
 
     auto requestInterceptor = new FileTypeRequestInterceptor(this);
     setRequestInterceptor(requestInterceptor);
+#endif
+
 }
 #endif
\ No newline at end of file
diff --git a/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp b/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp
index 25866ad395..7178bc89ac 100644
--- a/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp
+++ b/libraries/ui/src/ui/types/FileTypeRequestInterceptor.cpp
@@ -22,4 +22,4 @@ void FileTypeRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info
     RequestFilters::interceptFileType(info);
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.h b/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.h
index e38549937e..5c5f30ce0b 100644
--- a/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.h
+++ b/libraries/ui/src/ui/types/HFTabletWebEngineRequestInterceptor.h
@@ -11,14 +11,26 @@
 
 #ifndef hifi_HFTabletWebEngineRequestInterceptor_h
 #define hifi_HFTabletWebEngineRequestInterceptor_h
+#include <QtCore/QObject>
 
+#ifndef ANDROID
 #include <QWebEngineUrlRequestInterceptor>
+#endif
 
-class HFTabletWebEngineRequestInterceptor : public QWebEngineUrlRequestInterceptor {
+class HFTabletWebEngineRequestInterceptor
+#ifndef ANDROID
+        : public QWebEngineUrlRequestInterceptor
+#endif
+{
 public:
-    HFTabletWebEngineRequestInterceptor(QObject* parent) : QWebEngineUrlRequestInterceptor(parent) {};
-
-    virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
+    HFTabletWebEngineRequestInterceptor(QObject* parent) 
+#ifndef ANDROID 
+	: QWebEngineUrlRequestInterceptor(parent)
+#endif
+ {};
+#ifndef ANDROID 
+	virtual void interceptRequest(QWebEngineUrlRequestInfo& info) override;
+#endif
 };
 
 #endif // hifi_HFWebEngineRequestInterceptor_h
diff --git a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp
index 381bdb10bd..a443a7c160 100644
--- a/libraries/ui/src/ui/types/HFWebEngineProfile.cpp
+++ b/libraries/ui/src/ui/types/HFWebEngineProfile.cpp
@@ -17,14 +17,16 @@
 
 static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
 
-HFWebEngineProfile::HFWebEngineProfile(QObject* parent) :
-    QQuickWebEngineProfile(parent)
+HFWebEngineProfile::HFWebEngineProfile(QObject* parent) 
+#ifndef ANDROID 
+	: QQuickWebEngineProfile(parent)
+#endif
 {
-    setStorageName(QML_WEB_ENGINE_STORAGE_NAME);
-
+#ifndef ANDROID  setStorageName(QML_WEB_ENGINE_STORAGE_NAME);
     // we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
-    auto requestInterceptor = new HFWebEngineRequestInterceptor(this);
+   auto requestInterceptor = new HFWebEngineRequestInterceptor(this);
     setRequestInterceptor(requestInterceptor);
+#endif
 }
 
 #endif
\ No newline at end of file
diff --git a/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp b/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp
index 5a11c32efa..cecdddd2b6 100644
--- a/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp
+++ b/libraries/ui/src/ui/types/HFWebEngineRequestInterceptor.cpp
@@ -22,4 +22,4 @@ void HFWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& i
     RequestFilters::interceptHFWebEngineRequest(info);
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/libraries/ui/src/ui/types/RequestFilters.cpp b/libraries/ui/src/ui/types/RequestFilters.cpp
index 4cd51c6d98..0553d94df5 100644
--- a/libraries/ui/src/ui/types/RequestFilters.cpp
+++ b/libraries/ui/src/ui/types/RequestFilters.cpp
@@ -79,4 +79,4 @@ void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) {
         info.setHttpHeader(CONTENT_HEADER.toLocal8Bit(), TYPE_VALUE.toLocal8Bit());
     }
 }
-#endif
\ No newline at end of file
+#endif