mirror of
https://github.com/servo/servo.git
synced 2025-08-21 05:15:33 +01:00
Android life cycle improvements and Gradle integration
This commit is contained in:
parent
350d9c6c47
commit
7a2a90959e
30 changed files with 945 additions and 634 deletions
299
support/android/apk/app/build.gradle
Normal file
299
support/android/apk/app/build.gradle
Normal file
|
@ -0,0 +1,299 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
import groovy.io.FileType
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
import java.util.regex.Matcher
|
||||
import java.util.regex.Pattern
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion "25.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.mozilla.servo"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 25
|
||||
versionCode 1
|
||||
versionName "1.0.0"
|
||||
jackOptions {
|
||||
enabled true
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
incremental false
|
||||
}
|
||||
|
||||
splits {
|
||||
density {
|
||||
enable false
|
||||
}
|
||||
abi {
|
||||
enable false
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java.srcDirs = ['src/main/java']
|
||||
assets.srcDirs = ['../../../../resources']
|
||||
}
|
||||
armDebug {
|
||||
jniLibs.srcDirs = [getJniLibsPath(true, 'arm')]
|
||||
}
|
||||
armRelease {
|
||||
jniLibs.srcDirs = [getJniLibsPath(false, 'arm')]
|
||||
}
|
||||
armv7Debug {
|
||||
jniLibs.srcDirs = [getJniLibsPath(true, 'armv7')]
|
||||
}
|
||||
armv7Release {
|
||||
jniLibs.srcDirs = [getJniLibsPath(false, 'armv7')]
|
||||
}
|
||||
arm64Debug {
|
||||
jniLibs.srcDirs = [getJniLibsPath(true, 'arm64')]
|
||||
}
|
||||
arm64Release {
|
||||
jniLibs.srcDirs = [getJniLibsPath(false, 'arm64')]
|
||||
}
|
||||
x86Debug {
|
||||
jniLibs.srcDirs = [getJniLibsPath(true, 'x86')]
|
||||
}
|
||||
x86Release {
|
||||
jniLibs.srcDirs = [getJniLibsPath(false, 'x86')]
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
// Default debug and release build types are used as templates
|
||||
debug {
|
||||
jniDebuggable true
|
||||
}
|
||||
|
||||
release {
|
||||
signingConfig signingConfigs.debug // Change this to sign with a production key
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
||||
// Custom build types
|
||||
armDebug {
|
||||
initWith(debug)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('arm')
|
||||
}
|
||||
}
|
||||
armRelease {
|
||||
initWith(release)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('arm')
|
||||
}
|
||||
}
|
||||
armv7Debug {
|
||||
initWith(debug)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('armv7')
|
||||
}
|
||||
}
|
||||
armv7Release {
|
||||
initWith(release)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('armv7')
|
||||
}
|
||||
}
|
||||
arm64Debug {
|
||||
initWith(debug)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('arm64')
|
||||
}
|
||||
}
|
||||
arm64Release {
|
||||
initWith(release)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('arm64')
|
||||
}
|
||||
}
|
||||
x86Debug {
|
||||
initWith(debug)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('x86')
|
||||
}
|
||||
}
|
||||
x86Release {
|
||||
initWith(release)
|
||||
ndk {
|
||||
abiFilters getNDKAbi('x86')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore default 'debug' and 'release' build types
|
||||
variantFilter { variant ->
|
||||
if(variant.buildType.name.equals('release') || variant.buildType.name.equals('debug')) {
|
||||
variant.setIgnore(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Define apk output directory
|
||||
applicationVariants.all { variant ->
|
||||
variant.outputs.each { output ->
|
||||
def name = variant.buildType.name
|
||||
output.outputFile = new File(getApkPath(isDebug(name), getArch(name)))
|
||||
}
|
||||
}
|
||||
|
||||
// Call our custom NDK Build task using flavor parameters
|
||||
tasks.all {
|
||||
compileTask ->
|
||||
Pattern pattern = Pattern.compile(/^transformJackWithJackFor([\w\d]+)(Debug|Release)/);
|
||||
Matcher matcher = pattern.matcher(compileTask.name);
|
||||
// You can use this alternative pattern when jackCompiler is disabled
|
||||
// Pattern pattern = Pattern.compile(/^compile([\w\d]+)(Debug|Release)/);
|
||||
// Matcher matcher = pattern.matcher(compileTask.name);
|
||||
if (!matcher.find()) {
|
||||
return
|
||||
}
|
||||
|
||||
def taskName = "ndkbuild" + compileTask.name
|
||||
tasks.create(name: taskName, type: Exec) {
|
||||
def debug = compileTask.name.contains("Debug")
|
||||
def arch = matcher.group(1)
|
||||
commandLine getNdkDir(),
|
||||
'APP_BUILD_SCRIPT=../jni/Android.mk',
|
||||
'NDK_APPLICATION_MK=../jni/Application.mk',
|
||||
'NDK_LIBS_OUT=' + getJniLibsPath(debug, arch),
|
||||
'NDK_OUT=' + getTargetDir(debug, arch) + '/apk/obj',
|
||||
'NDK_DEBUG=' + (debug ? '1' : '0'),
|
||||
'APP_ABI=' + getNDKAbi(arch),
|
||||
'SERVO_TARGET_DIR=' + getTargetDir(debug, arch)
|
||||
}
|
||||
|
||||
compileTask.dependsOn taskName
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//Dependency list
|
||||
def deps = [
|
||||
new ServoDependency("blurdroid.jar", "blurdroid")
|
||||
]
|
||||
|
||||
// Iterate all build types and dependencies
|
||||
// For each dependency call the proper compile command and set the correct dependency path
|
||||
def list = ['arm', 'armv7', 'arm64', 'x86']
|
||||
for (arch in list) {
|
||||
for (debug in [true, false]) {
|
||||
String basePath = getTargetDir(debug, arch) + "/build"
|
||||
String cmd = arch + (debug ? "Debug" : "Release") + "Compile"
|
||||
|
||||
for (ServoDependency dep: deps) {
|
||||
String path = findDependencyPath(basePath, dep.fileName, dep.folderFilter)
|
||||
if (path) {
|
||||
"${cmd}" files(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Utility methods
|
||||
String getTargetDir(boolean debug, String arch) {
|
||||
def basePath = project.rootDir.getParentFile().getParentFile().getParentFile().absolutePath
|
||||
return basePath + '/target/' + getRustTarget(arch) + '/' + (debug ? 'debug' : 'release')
|
||||
}
|
||||
|
||||
String getApkPath(boolean debug, String arch) {
|
||||
return getTargetDir(debug, arch) + '/servo.apk'
|
||||
}
|
||||
|
||||
String getJniLibsPath(boolean debug, String arch) {
|
||||
return getTargetDir(debug, arch) + '/apk/jniLibs'
|
||||
}
|
||||
|
||||
String getArch(String buildType) {
|
||||
return buildType.replaceAll(/(Debug|Release)/, '')
|
||||
}
|
||||
|
||||
boolean isDebug(String buildType) {
|
||||
return buildType.contains("Debug")
|
||||
}
|
||||
|
||||
String getRustTarget(String arch) {
|
||||
switch (arch.toLowerCase()) {
|
||||
case 'arm' : return 'arm-linux-androideabi'
|
||||
case 'armv7' : return 'armv7-linux-androideabi'
|
||||
case 'arm64' : return 'aarch64-linux-android'
|
||||
case 'x86' : return 'x86'
|
||||
default: throw new GradleException("Invalid target architecture " + arch)
|
||||
}
|
||||
}
|
||||
|
||||
String getNDKAbi(String arch) {
|
||||
switch (arch.toLowerCase()) {
|
||||
case 'arm' : return 'armeabi'
|
||||
case 'armv7' : return 'armeabi-v7a'
|
||||
case 'arm64' : return 'arm64-v8a'
|
||||
case 'x86' : return 'x86'
|
||||
default: throw new GradleException("Invalid target architecture " + arch)
|
||||
}
|
||||
}
|
||||
|
||||
String getNdkDir() {
|
||||
// Read environment variable used in rust build system
|
||||
String ndkDir = System.getenv('ANDROID_NDK')
|
||||
if (ndkDir == null) {
|
||||
ndkDir = System.getenv('ANDROID_NDK_HOME')
|
||||
}
|
||||
if (ndkDir == null) {
|
||||
// Fallback to ndkDir in local.properties
|
||||
def rootDir = project.rootDir
|
||||
def localProperties = new File(rootDir, "local.properties")
|
||||
Properties properties = new Properties()
|
||||
localProperties.withInputStream { instr ->
|
||||
properties.load(instr)
|
||||
}
|
||||
|
||||
ndkDir = properties.getProperty('ndk.dir')
|
||||
}
|
||||
|
||||
def cmd = Os.isFamily(Os.FAMILY_WINDOWS) ? 'ndk-build.cmd' : 'ndk-build'
|
||||
def ndkbuild = new File(ndkDir + '/' + cmd)
|
||||
if (!ndkbuild.exists()) {
|
||||
throw new GradleException("Please set a valid NDK_HOME environment variable" +
|
||||
"or ndk.dir path in local.properties file");
|
||||
}
|
||||
return ndkbuild.absolutePath
|
||||
}
|
||||
|
||||
// folderFilter can be used to improve search performance
|
||||
String findDependencyPath(String basePath, String filename, String folderFilter) {
|
||||
File path = new File(basePath);
|
||||
if (!path.exists()) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (folderFilter) {
|
||||
path.eachDir {
|
||||
if (it.name.contains(folderFilter)) {
|
||||
path = new File(it.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
def result = ''
|
||||
path.eachFileRecurse(FileType.FILES) {
|
||||
if(it.name.equals(filename)) {
|
||||
result = it.absolutePath
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
class ServoDependency {
|
||||
public ServoDependency(String fileName, String folderFilter = null) {
|
||||
this.fileName = fileName;
|
||||
this.folderFilter = folderFilter;
|
||||
}
|
||||
public String fileName;
|
||||
public String folderFilter;
|
||||
}
|
49
support/android/apk/app/src/main/AndroidManifest.xml
Normal file
49
support/android/apk/app/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- BEGIN_INCLUDE(manifest) -->
|
||||
<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: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"/>
|
||||
|
||||
<application android:label="Servo" android:icon="@mipmap/servo">
|
||||
<activity android:name=".MainActivity"
|
||||
android:label="Servo"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize">
|
||||
<meta-data android:name="android.app.lib_name" android:value="servo" />
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- Web browser intents -->
|
||||
<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" />
|
||||
<data android:scheme="data" />
|
||||
<data android:scheme="javascript" />
|
||||
</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="file" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:mimeType="text/html"/>
|
||||
<data android:mimeType="text/plain"/>
|
||||
<data android:mimeType="application/xhtml+xml"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
<!-- END_INCLUDE(manifest) -->
|
|
@ -0,0 +1,299 @@
|
|||
package com.mozilla.servo;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
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.View;
|
||||
import android.view.WindowManager;
|
||||
import android.webkit.URLUtil;
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
try {
|
||||
extractAssets();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject preferences = loadPreferences();
|
||||
boolean keepScreenOn = preferences.optBoolean("shell.keep_screen_on.enabled", false);
|
||||
mFullScreen = !preferences.optBoolean("shell.native-titlebar.enabled", false);
|
||||
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);
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
// Handle keep screen on preference
|
||||
if (keepScreenOn) {
|
||||
keepScreenOn();
|
||||
}
|
||||
|
||||
// Handle full screen preference
|
||||
if (mFullScreen) {
|
||||
addFullScreenListener();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
Log.d(LOGTAG, "onStop");
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
Log.d(LOGTAG, "onPause");
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Log.d(LOGTAG, "onPause");
|
||||
if (mFullScreen) {
|
||||
setFullScreen();
|
||||
}
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus && mFullScreen) {
|
||||
setFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
// keep the device's screen turned on and bright.
|
||||
private void keepScreenOn() {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@TargetApi(19)
|
||||
private int getImmersiveFlag() {
|
||||
return View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsToExtractAssets(String path) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
int version = BuildConfig.VERSION_CODE;
|
||||
|
||||
if (!new File(path).exists()) {
|
||||
// Assets folder doesn't exist, resources need to be copied
|
||||
prefs.edit().putInt(PREF_KEY_RESOURCES_SYNC, version).apply();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (version != prefs.getInt(PREF_KEY_RESOURCES_SYNC, -1)) {
|
||||
// Also force a reextract when the version changes and the resources may be updated
|
||||
// This can be improved by generating a hash or version number of the resources
|
||||
// instead of using version code of the app
|
||||
prefs.edit().putInt(PREF_KEY_RESOURCES_SYNC, version).apply();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private File getAppDataDir() {
|
||||
File file = getExternalFilesDir(null);
|
||||
return file != null ? file : getFilesDir();
|
||||
}
|
||||
/**
|
||||
* extracts assets/ in the APK to /sdcard/servo.
|
||||
*/
|
||||
private void extractAssets() throws IOException {
|
||||
String path = getAppDataDir().getAbsolutePath();
|
||||
if (!needsToExtractAssets(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZipFile zipFile = null;
|
||||
File targetDir = new File(path);
|
||||
try {
|
||||
zipFile = new ZipFile(this.getApplicationInfo().sourceDir);
|
||||
for (Enumeration<? extends ZipEntry> e = zipFile.entries(); e.hasMoreElements(); ) {
|
||||
ZipEntry entry = e.nextElement();
|
||||
if (entry.isDirectory() || !entry.getName().startsWith("assets/")) {
|
||||
continue;
|
||||
}
|
||||
File targetFile = new File(targetDir, entry.getName().substring("assets/".length()));
|
||||
targetFile.getParentFile().mkdirs();
|
||||
byte[] tempBuffer = new byte[(int)entry.getSize()];
|
||||
BufferedInputStream is = null;
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
is = new BufferedInputStream(zipFile.getInputStream(entry));
|
||||
os = new FileOutputStream(targetFile);
|
||||
is.read(tempBuffer);
|
||||
os.write(tempBuffer);
|
||||
} finally {
|
||||
try {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
if (os != null) {
|
||||
os.close();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOGTAG, Log.getStackTraceString(ex));
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (zipFile != null) {
|
||||
zipFile.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, Log.getStackTraceString(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
BIN
support/android/apk/app/src/main/res/mipmap/servo.png
Normal file
BIN
support/android/apk/app/src/main/res/mipmap/servo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 509 KiB |
Loading…
Add table
Add a link
Reference in a new issue