Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sdk and Gradle update #21160

Closed
wants to merge 8 commits into from

minimal Android app that relies on libsimpleservo

  • Loading branch information
paulrouget committed Jul 10, 2018
commit dab401b1dac259c8bb54872299cbe29cf03088e2
@@ -211,6 +211,9 @@ dependencies {
googlevrCompile 'com.google.vr:sdk-base:1.70.0'
googlevrCompile(name:'GVRService', ext:'aar')
oculusvrCompile(name:'OVRService', ext:'aar')

// compile is deprecated. Will become "implementation" once we upgrade graddle.
compile 'com.android.support.constraint:constraint-layout:1.0.0'
}

// Utility methods
@@ -3,11 +3,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"
package="com.mozilla.servo">

<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:glEsVersion="0x00030000" android:required="true" />
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

@@ -1,248 +1,146 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */


package com.mozilla.servo;
import android.annotation.TargetApi;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.webkit.URLUtil;
import android.widget.FrameLayout;

import com.mozilla.servo.BuildConfig;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.System;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;


public class MainActivity extends android.app.NativeActivity {
private static final String LOGTAG = "Servo";
private boolean mFullScreen = false;
private static final String PREF_KEY_RESOURCES_SYNC = "res_sync_v";

static {
Log.i(LOGTAG, "Loading the NativeActivity");

// Libaries should be loaded in reverse dependency order
System.loadLibrary("c++_shared");
System.loadLibrary("servo");
}
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;

@Override
public void onCreate(Bundle savedInstanceState) {
final Intent intent = getIntent();
if (intent != null && intent.getAction().equals(Intent.ACTION_VIEW)) {
final String url = intent.getDataString();
if (url != null && URLUtil.isValidUrl(url)) {
Log.d(LOGTAG, "Received url "+url);
set_url(url);
}
}
import com.mozilla.servoview.ServoView;

JSONObject preferences = loadPreferences();
public class MainActivity extends Activity implements ServoView.Client {

boolean keepScreenOn = false;
private static final String LOGTAG = "MainActivity";

if (BuildConfig.FLAVOR.contains("vr")) {
// Force fullscreen mode and keep screen on for VR experiences.
keepScreenOn = true;
mFullScreen = true;
}
else {
keepScreenOn = preferences.optBoolean("shell.keep_screen_on.enabled", false);
mFullScreen = !preferences.optBoolean("shell.native-titlebar.enabled", false);
ServoView mServoView;
Button mBackButton;
Button mFwdButton;
Button mReloadButton;
Button mStopButton;
EditText mUrlField;
ProgressBar mProgressBar;

String orientation = preferences.optString("shell.native-orientation", "both");

// Handle orientation preference
if (orientation.equalsIgnoreCase("portrait")) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
else if (orientation.equalsIgnoreCase("landscape")) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// NativeActivity ignores the Android view hierarchy because it’s designed
// to take over the surface from the window to directly draw to it.
// Inject a custom SurfaceView in order to support adding views on top of the browser.
// (e.g. Native Banners, Daydream GVRLayout or other native views)
getWindow().takeSurface(null);
FrameLayout layout = new FrameLayout(this);
layout.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT));
SurfaceView nativeSurface = new SurfaceView(this);
nativeSurface.getHolder().addCallback(this);
layout.addView(nativeSurface, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
setContentView(layout);

// Handle keep screen on preference
if (keepScreenOn) {
keepScreenOn();
}
mServoView = (ServoView)findViewById(R.id.servoview);
mBackButton = (Button)findViewById(R.id.backbutton);
mFwdButton = (Button)findViewById(R.id.forwardbutton);
mReloadButton = (Button)findViewById(R.id.reloadbutton);
mStopButton = (Button)findViewById(R.id.stopbutton);
mUrlField = (EditText)findViewById(R.id.urlfield);
mProgressBar = (ProgressBar)findViewById(R.id.progressbar);

mServoView.setClient(this);
mBackButton.setEnabled(false);
mFwdButton.setEnabled(false);

mServoView.requestFocus();

// Handle full screen preference
if (mFullScreen) {
addFullScreenListener();
String args = getIntent().getStringExtra("servoargs");
if (args != null) {
mServoView.setServoArgs(args);
}
}

@Override
protected void onStop() {
Log.d(LOGTAG, "onStop");
super.onStop();
setupUrlField();
}

@Override
protected void onPause() {
Log.d(LOGTAG, "onPause");
super.onPause();
private void setupUrlField() {
mUrlField.setOnEditorActionListener((v, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
loadUrlFromField();
mServoView.requestFocus();
return true;
}
return false;
});
mUrlField.setOnFocusChangeListener((v, hasFocus) -> {
if(v.getId() == R.id.urlfield && !hasFocus) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
assert imm != null;
imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
});
}

@Override
protected void onResume() {
Log.d(LOGTAG, "onPause");
if (mFullScreen) {
setFullScreen();
private void loadUrlFromField() {
String text = mUrlField.getText().toString();
text = text.trim();
String uri;

if (text.contains(" ") || !text.contains(".")) {
uri = URLUtil.composeSearchUrl(text, "https://duckduckgo.com/html/?q=%s", "%s");
} else {
uri = URLUtil.guessUrl(text);
}
super.onResume();

mServoView.loadUri(Uri.parse(uri));
}

@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && mFullScreen) {
setFullScreen();
}
public void onReloadClicked(View v) {
mServoView.reload();
}

// keep the device's screen turned on and bright.
private void keepScreenOn() {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
public void onBackClicked(View v) {
mServoView.goBack();
}

// Dim toolbar and make the view fullscreen
private void setFullScreen() {
int flags = 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 // Hides navigation bar
| View.SYSTEM_UI_FLAG_FULLSCREEN; // Hides status bar
if( android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
flags |= getImmersiveFlag();
} else {
flags |= View.SYSTEM_UI_FLAG_LOW_PROFILE;
}
getWindow().getDecorView().setSystemUiVisibility(flags);
public void onForwardClicked(View v) {
mServoView.goForward();
}

@TargetApi(19)
private int getImmersiveFlag() {
return View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
public void onStopClicked(View v) {
mServoView.stop();
}

private void addFullScreenListener() {
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener(
new View.OnSystemUiVisibilityChangeListener() {
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
setFullScreen();
}
}
});
@Override
public void onLoadStarted() {
mReloadButton.setEnabled(false);
mStopButton.setEnabled(true);
mReloadButton.setVisibility(View.GONE);
mStopButton.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
}

private String loadAsset(String file) {
InputStream is = null;
BufferedReader reader = null;
try {
is = getAssets().open(file);
reader = new BufferedReader(new InputStreamReader(is));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append('\n');
}
return result.toString();
} catch (IOException e) {
Log.e(LOGTAG, Log.getStackTraceString(e));
return null;
}
finally {
try {
if (reader != null) {
reader.close();
}
if (is != null) {
is.close();
}
} catch (Exception e) {
Log.e(LOGTAG, Log.getStackTraceString(e));
}
}
@Override
public void onLoadEnded() {
mReloadButton.setEnabled(true);
mStopButton.setEnabled(false);
mReloadButton.setVisibility(View.VISIBLE);
mStopButton.setVisibility(View.GONE);
mProgressBar.setVisibility(View.INVISIBLE);
}

private JSONObject loadPreferences() {
String json = loadAsset("prefs.json");
try {
return new JSONObject(json);
} catch (JSONException e) {
Log.e(LOGTAG, Log.getStackTraceString(e));
return new JSONObject();
}
@Override
public void onTitleChanged(String title) {
}

private File getAppDataDir() {
File file = getExternalFilesDir(null);
return file != null ? file : getFilesDir();
@Override
public void onUrlChanged(String url) {
mUrlField.setText(url);
}

private void set_url(String url) {
try {
File file = new File(getAppDataDir() + "/android_params");
if (!file.exists()) {
file.createNewFile();
}
PrintStream out = new PrintStream(new FileOutputStream(file, false));
out.println("# The first line here should be the \"servo\" argument (without quotes) and the");
out.println("# last should be the URL to load.");
out.println("# Blank lines and those beginning with a '#' are ignored.");
out.println("# Each line should be a separate parameter as would be parsed by the shell.");
out.println("# For example, \"servo -p 10 http://en.wikipedia.org/wiki/Rust\" would take 4");
out.println("# lines (the \"-p\" and \"10\" are separate even though they are related).");
out.println("servo");
out.println("-w");
String absUrl = url.replace("file:///storage/emulated/0/", "/sdcard/");
out.println(absUrl);
out.flush();
out.close();
} catch (Exception e) {
Log.e(LOGTAG, Log.getStackTraceString(e));
}
@Override
public void onHistoryChanged(boolean canGoBack, boolean canGoForward) {
mBackButton.setEnabled(canGoBack);
mFwdButton.setEnabled(canGoForward);
}

}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.