Added possibility to build OsmAnd as library

This commit is contained in:
max-klaus 2020-11-20 19:24:38 +03:00
parent ae63a0edd0
commit 240714b4e0
5 changed files with 552 additions and 39 deletions

521
OsmAnd/build.gradle.lib Normal file
View file

@ -0,0 +1,521 @@
//apply plugin: 'com.android.application'
apply plugin: 'com.android.library'
// Global Parameters accepted
// TARGET_APP_NAME - app name
// APK_NUMBER_VERSION - version number of apk
// APK_VERSION_SUFFIX - build number like #99999Z, appended (for dev builds) to Manifest's versionName as X.X.X#99999Z
// Z means flavor: M=-master, D=-main-default, B=-Blackberry, Des=-design, MQA=-main-qt-arm, MQDA=-main-qt-default-arm, S=-sherpafy
// APP_EDITION - date stamp of builds
// APP_FEATURES - features +play_market +gps_status -parking_plugin -blackberry -free_version -amazon
// 1. To be done Filter fonts
// <unzip src="OsmAndCore_android.aar" dest=".">
// <patternset>
// <include name="assets/**/map/fonts/OpenSans/*"/>
// <include name="assets/**/map/fonts/NotoSans/*"/>
// </patternset>
// </unzip>
// Less important
task printc {
configurations.each { if(it.isCanBeResolved()) println it.name }
}
android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
// compileNdkVersion "android-ndk-r17b"
signingConfigs {
development {
storeFile file("../keystores/debug.keystore")
storePassword "android"
keyAlias "androiddebugkey"
keyPassword "android"
}
publishing {
storeFile file("/var/lib/jenkins/osmand_key")
storePassword System.getenv("OSMAND_APK_PASSWORD")
keyAlias "osmand"
keyPassword System.getenv("OSMAND_APK_PASSWORD")
}
}
defaultConfig {
minSdkVersion System.getenv("MIN_SDK_VERSION") ? System.getenv("MIN_SDK_VERSION").toInteger() : 15
targetSdkVersion 29
versionCode 390
versionCode System.getenv("APK_NUMBER_VERSION") ? System.getenv("APK_NUMBER_VERSION").toInteger() : versionCode
multiDexEnabled true
versionName "3.9.0"
versionName System.getenv("APK_VERSION")? System.getenv("APK_VERSION").toString(): versionName
versionName System.getenv("APK_VERSION_SUFFIX")? versionName + System.getenv("APK_VERSION_SUFFIX").toString(): versionName
// Stops the Gradle plugins automatic rasterization of vectors
// vectorDrawables.generatedDensities = ['hdpi']
vectorDrawables.useSupportLibrary = true
}
lintOptions {
lintConfig file("lint.xml")
abortOnError false
warningsAsErrors false
}
/*
bundle {
language {
// Specifies that the app bundle should not support
// configuration APKs for language resources. These
// resources are instead packaged with each base and
// dynamic feature APK.
enableSplit = false
}
}
*/
// related to kuromoji
//packagingOptions {
// exclude '/META-INF/CONTRIBUTORS.md'
// exclude '/META-INF/LICENSE.md'
// exclude '/META-INF/NOTICE.md'
//}
// This is from OsmAndCore_android.aar - for some reason it's not inherited
aaptOptions {
// Don't compress any embedded resources
noCompress "qz"
cruncherEnabled = false
// Flag notifies aapt to keep the attribute IDs around
// additionalParameters "--no-version-vectors"
}
dexOptions {
javaMaxHeapSize "4g"
}
sourceSets {
main {
manifest.srcFile "AndroidManifest.xml"
jni.srcDirs = []
jniLibs.srcDirs = ["libs"]
aidl.srcDirs = ["src"]
java.srcDirs = ["src", "src-google"]
resources.srcDirs = ["src"]
renderscript.srcDirs = ["src"]
res.srcDirs = ["res"]
assets.srcDirs = ["assets"]
}
debug {
manifest.srcFile "AndroidManifest-debug.xml"
}
/*
full {
java.srcDirs = ["src-google"]
}
free {
java.srcDirs = ["src-google"]
manifest.srcFile "AndroidManifest-free.xml"
}
freedev {
java.srcDirs = ["src-google"]
manifest.srcFile "AndroidManifest-freedev.xml"
}
freehuawei {
java.srcDirs = ["src-huawei"]
manifest.srcFile "AndroidManifest-freehuawei.xml"
}
*/
legacy {
jniLibs.srcDirs = ["libc++"]
}
}
flavorDimensions "coreversion", "abi"
productFlavors {
// ABI
armv7 {
dimension "abi"
ndk {
abiFilter 'armeabi-v7a'
}
}
arm64 {
dimension "abi"
ndk {
abiFilter 'arm64-v8a'
}
}
x86 {
dimension "abi"
ndk {
abiFilters 'x86', 'x86_64'
}
}
armonly {
dimension "abi"
ndk {
abiFilters 'arm64-v8a', 'armeabi-v7a'
}
}
fat {
dimension "abi"
ndk {
abiFilters 'arm64-v8a', 'x86', 'x86_64', 'armeabi-v7a'
}
}
/*
// Version
freedev {
dimension "version"
applicationId "net.osmand.dev"
// resConfig "en"
}
free {
dimension "version"
applicationId "net.osmand"
}
full {
dimension "version"
applicationId "net.osmand.plus"
}
freehuawei {
dimension "version"
applicationId "net.osmand.huawei"
}
*/
// CoreVersion
// Build that doesn't include 3D OpenGL
legacy {
dimension "coreversion"
}
// Build that includes 3D OpenGL release
qtcore {
dimension "coreversion"
}
// Build that includes 3D OpenGL debug
qtcoredebug {
dimension "coreversion"
}
}
buildTypes {
debug {
buildConfigField "String", "OPR_BASE_URL", "\"https://test.openplacereviews.org/\""
buildConfigField "String", "OSM_OAUTH_CONSUMER_KEY", "\"Ti2qq3fo4i4Wmuox3SiWRIGq3obZisBHnxmcM05y\""
buildConfigField "String", "OSM_OAUTH_CONSUMER_SECRET", "\"lxulb3HYoMmd2cC4xxNe1dyfRMAY8dS0eNihJ0DM\""
signingConfig signingConfigs.development
}
release {
buildConfigField "String", "OPR_BASE_URL", "\"https://test.openplacereviews.org/\""
buildConfigField "String", "OSM_OAUTH_CONSUMER_KEY", "\"Ti2qq3fo4i4Wmuox3SiWRIGq3obZisBHnxmcM05y\""
buildConfigField "String", "OSM_OAUTH_CONSUMER_SECRET", "\"lxulb3HYoMmd2cC4xxNe1dyfRMAY8dS0eNihJ0DM\""
signingConfig signingConfigs.publishing
}
}
}
def replaceNoTranslate(line) {
if (line.contains("\"app_name\"") && System.getenv("TARGET_APP_NAME")) {
return line.replaceAll(">[^<]*<", ">" + System.getenv("TARGET_APP_NAME") + "<")
}
if (line.contains("\"app_name_free\"") && System.getenv("TARGET_APP_NAME")) {
return line.replaceAll(">[^<]*<", ">" + System.getenv("TARGET_APP_NAME") + "<")
}
if (line.contains("\"app_edition\"") && System.getenv("APP_EDITION")) {
return line.replaceAll(">[^<]*<", ">" + System.getenv("APP_EDITION") + "<")
}
if (line.contains("\"versionFeatures\"") && System.getenv("APP_FEATURES")) {
return line.replaceAll(">[^<]*<", ">" + System.getenv("APP_FEATURES") + "<")
}
return line;
}
task updateNoTranslate(type: Copy) {
from('.') {
include 'no_translate.xml'
filter {
line -> replaceNoTranslate(line);
}
}
into 'res/values/'
}
task validateTranslate {
println "Validating translations"
file("res").eachFileRecurse groovy.io.FileType.FILES, {
if (it.name == "strings.xml" || it.name == "phrases.xml") {
it.eachLine { line ->
if (line.contains("\$ s") || line.contains("\$ d") || line.contains("\$ f") ||
line.contains(" \$s") || line.contains(" \$d") || line.contains(" \$f") ||
line.contains("1\$ ") || line.contains("2\$ ") || line.contains("3\$ ") ||
line.contains("%1s") || line.contains(" 1\$s") ||
(line.contains("% \$") || line.contains("% 1") || line.contains("% 2") ||
line.contains("% 3") || line.contains("% s"))) {
throw new GradleException("Incorrect translation " + it.getAbsolutePath() + " " + line);
}
}
}
}
}
task downloadWorldMiniBasemap {
doLast {
ant.get(src: 'http://builder.osmand.net/basemap/World_basemap_mini_2.obf', dest: 'assets/World_basemap_mini.obf', skipexisting: 'true')
}
}
task collectVoiceAssets(type: Sync) {
from "../../resources/voice"
into "assets/voice"
include "**/*.js"
}
task cleanNoTranslate(type: Delete) {
delete('res/values/no_translate.xml')
}
task collectFonts(type: Copy) {
from "../../resources/fonts"
from "../../resources/rendering_styles/fonts"
// from "../../resources/rendering_styles/fonts/OpenSans"
into "assets/fonts"
include "*.ttf"
}
task collectHelpContentsStyle(type: Copy) {
from("../../help/website/help/") {
include "style.css"
}
into "assets"
}
task collectHelpContentsAssets(type: Copy) {
from("../../help/website/help") {
include "about.html"
include "changes.html"
include "faq.html"
include "technical-articles.html"
include "map-legend.html"
}
from("../../help/website/feature_articles") {
include "*.html"
}
from("../../help/website/blog_articles") {
include "osmand-3-8-released.html"
}
into "assets/feature_articles"
}
task copyPoiCategories(type: Copy) {
from("../../resources/poi") {
include "poi_categories.json"
}
into "assets"
}
task copyMapShaderIcons(type: Sync) {
// from "../../resources/rendering_styles/style-icons/map-shaders-png"
// into "res/"
from "../../resources/rendering_styles/style-icons/map-shaders-vector"
into "res/drawable"
include "**/*.png", "**/*.xml"
preserve {
include '**/*'
exclude "**/h_*"
}
}
task copyMapPOIIcons(type: Sync) {
from "../../resources/rendering_styles/style-icons/map-icons-vector"
into "res/drawable/"
// from "../../resources/rendering_styles/style-icons/map-icons-png"
// into "res/"
include "**/*.png", "**/*.xml"
preserve {
include '**/*'
exclude "**/mm_*"
}
}
task copyLargePOIIcons(type: Sync) {
from "../../resources/rendering_styles/style-icons/poi-icons-vector"
into "res/drawable/"
include "**/*.png", "**/*.xml"
preserve {
include '**/*'
exclude "**/mx_*"
}
}
task copyWidgetIconsXhdpi(type: Sync) {
from "res/drawable-xxhdpi/"
into "res/drawable-large-xhdpi/"
include "**/widget_*.png", "**/widget_*.xml", "**/map_*.xml", "**/map_*.png"
preserve {
include '*'
exclude "**/widget_*.png", "**/widget_*.xml", "**/map_*.xml", "**/map_*.png"
}
}
task copyWidgetIconsHdpi(type: Sync) {
from "res/drawable-xhdpi/"
into "res/drawable-large-hdpi/"
include "**/widget_*.png", "**/widget_*.xml", "**/map_*.xml", "**/map_*.png"
preserve {
include '*'
exclude "**/widget_*.png", "**/widget_*.xml", "**/map_*.xml", "**/map_*.png"
}
}
task copyWidgetIcons(type: Sync) {
from "res/drawable-hdpi/"
into "res/drawable-large/"
include "**/widget_*.png", "**/widget_*.xml", "**/map_*.xml", "**/map_*.png"
preserve {
include '*'
exclude "**/widget_*.png", "**/widget_*.xml", "**/map_*.xml", "**/map_*.png"
}
}
task collectExternalResources {
dependsOn collectVoiceAssets,
collectFonts,
collectHelpContentsAssets,
collectHelpContentsStyle,
copyMapShaderIcons,
copyMapPOIIcons,
copyLargePOIIcons,
updateNoTranslate,
validateTranslate,
copyWidgetIcons,
copyWidgetIconsHdpi,
copyWidgetIconsXhdpi,
copyPoiCategories,
downloadWorldMiniBasemap
}
// Legacy core build
import org.apache.tools.ant.taskdefs.condition.Os
task buildOsmAndCore(type: Exec) {
Gradle gradle = getGradle()
String tskReqStr = gradle.getStartParameter().getTaskRequests().toString().toLowerCase()
String flavour = "";
if(!tskReqStr.contains("fat")) {
if(tskReqStr.contains("arm64")) {
flavour = flavour.length() == 0 ? "ARM64_ONLY" : ""
}
if(tskReqStr.contains("armv7")) {
flavour = flavour.length() == 0 ? "ARMV7_ONLY" : ""
}
if(tskReqStr.contains("armonly")) {
flavour = flavour.length() == 0 ? "ARM_ONLY" : ""
}
if(tskReqStr.contains("x86")) {
flavour = flavour.length() == 0 ? "X86_ONLY" : ""
}
}
description "Build Legacy OsmAndCore"
if (!Os.isFamily(Os.FAMILY_WINDOWS)) {
if(flavour.length() > 0) {
environment "$flavour", "1"
}
commandLine "bash", file("./old-ndk-build.sh").getAbsolutePath()
} else {
commandLine "cmd", "/c", "echo", "Not supported"
}
}
task cleanupDuplicatesInCore() {
dependsOn buildOsmAndCore
// doesn't work for legacy debug builds
doLast {
file("libc++/armeabi-v7a").mkdirs()
file("libs/armeabi-v7a/libc++_shared.so").renameTo(file("libc++/armeabi-v7a/libc++_shared.so"))
file("libc++/arm64-v8a").mkdirs()
file("libs/arm64-v8a/libc++_shared.so").renameTo(file("libc++/arm64-v8a/libc++_shared.so"))
file("libc++/x86").mkdirs()
file("libs/x86/libc++_shared.so").renameTo(file("libc++/x86/libc++_shared.so"))
file("libc++/x86_64").mkdirs()
file("libs/x86_64/libc++_shared.so").renameTo(file("libc++/x86_64/libc++_shared.so"))
}
}
afterEvaluate {
android.libraryVariants.all { variant ->
variant.javaCompiler.dependsOn(collectExternalResources, buildOsmAndCore, cleanupDuplicatesInCore)
}
Gradle gradle = getGradle()
String tskReqStr = gradle.getStartParameter().getTaskRequests().toString().toLowerCase()
if (tskReqStr.contains("huawei")) {
apply plugin: 'com.huawei.agconnect'
}
}
task appStart(type: Exec) {
// linux
commandLine 'adb', 'shell', 'am', 'start', '-n', 'net.osmand.plus/net.osmand.plus.activities.MapActivity'
// windows
// commandLine 'cmd', '/c', 'adb', 'shell', 'am', 'start', '-n', 'net.osmand.plus/net.osmand.plus.activities.MapActivity'
}
dependencies {
implementation project(path: ':OsmAnd-java', configuration: 'android')
implementation project(':OsmAnd-api')
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.gridlayout:gridlayout:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.preference:preference:1.1.0'
implementation fileTree(include: ['gnu-trove-osmand.jar', 'icu4j-49_1_patched.jar'], dir: 'libs')
implementation group: 'commons-logging', name: 'commons-logging', version: '1.2'
implementation 'commons-codec:commons-codec:1.11'
implementation 'it.unibo.alice.tuprolog:tuprolog:3.2.1'
implementation 'org.apache.commons:commons-compress:1.17'
implementation 'com.moparisthebest:junidecode:0.1.1'
implementation 'org.immutables:gson:2.5.0'
implementation 'com.vividsolutions:jts-core:1.14.0'
implementation 'com.google.openlocationcode:openlocationcode:1.0.4'
implementation 'com.android.billingclient:billing:2.0.3'
// turn off for now
//implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'me.zhanghai.android.materialprogressbar:library:1.4.2'
// JS core
implementation group: 'org.mozilla', name: 'rhino', version: '1.7.9'
// size restrictions
// implementation 'com.ibm.icu:icu4j:50.1'
// implementation 'net.sf.trove4j:trove4j:3.0.3'
qtcoreImplementation fileTree(include: ['QtAndroid.jar', 'QtAndroidBearer.jar'], dir: 'libs')
qtcoredebugImplementation fileTree(include: ['QtAndroid.jar', 'QtAndroidBearer.jar'], dir: 'libs')
legacyImplementation "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@jar"
qtcoredebugImplementation "net.osmand:OsmAndCore_androidNativeDebug:0.1-SNAPSHOT@aar"
qtcoredebugImplementation "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@aar"
qtcoreImplementation "net.osmand:OsmAndCore_androidNativeRelease:0.1-SNAPSHOT@aar"
qtcoreImplementation "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@aar"
implementation ("com.getkeepsafe.taptargetview:taptargetview:1.12.0"){
exclude group: 'com.android.support'
}
implementation 'com.github.PhilJay:MPAndroidChart:v3.0.1'
implementation ("com.github.HITGIF:TextFieldBoxes:1.4.5"){
exclude group: 'com.android.support'
}
implementation('com.github.scribejava:scribejava-apis:7.1.1'){
exclude group: "com.fasterxml.jackson.core"
}
implementation 'com.jaredrummler:colorpicker:1.1.0'
//freehuaweiImplementation 'com.huawei.hms:iap:5.0.2.300'
}

View file

@ -304,9 +304,6 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
}
mapActions = new MapActivityActions(this);
mapLayers = new MapActivityLayers(this);
if (mapViewTrackingUtilities == null) {
mapViewTrackingUtilities = new MapViewTrackingUtilities(app);
}
dashboardOnMap.createDashboardView();
checkAppInitialization();

View file

@ -819,7 +819,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
}
}
});
mapInfoLayer.registerSideWidget(recordControl, new AudioVideoNotesWidgetState(app), "audionotes", false, 32);
mapInfoLayer.registerSideWidget(recordControl, new AudioVideoNotesWidgetState(app, AV_DEFAULT_ACTION), "audionotes", false, 32);
mapInfoLayer.recreateControls();
}
}
@ -2153,20 +2153,23 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
return DashAudioVideoNotesFragment.FRAGMENT_DATA;
}
public class AudioVideoNotesWidgetState extends WidgetState {
public static class AudioVideoNotesWidgetState extends WidgetState {
private final CommonPreference<Integer> defaultActionSetting;
private static final int AV_WIDGET_STATE_ASK = R.id.av_notes_widget_state_ask;
private static final int AV_WIDGET_STATE_AUDIO = R.id.av_notes_widget_state_audio;
private static final int AV_WIDGET_STATE_VIDEO = R.id.av_notes_widget_state_video;
private static final int AV_WIDGET_STATE_PHOTO = R.id.av_notes_widget_state_photo;
AudioVideoNotesWidgetState(OsmandApplication ctx) {
AudioVideoNotesWidgetState(OsmandApplication ctx, CommonPreference<Integer> defaultActionSetting) {
super(ctx);
this.defaultActionSetting = defaultActionSetting;
}
@Override
public int getMenuTitleId() {
Integer action = AV_DEFAULT_ACTION.get();
Integer action = defaultActionSetting.get();
switch (action) {
case AV_DEFAULT_ACTION_AUDIO:
return R.string.av_def_action_audio;
@ -2181,7 +2184,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
@Override
public int getMenuIconId() {
Integer action = AV_DEFAULT_ACTION.get();
Integer action = defaultActionSetting.get();
switch (action) {
case AV_DEFAULT_ACTION_AUDIO:
return R.drawable.ic_action_micro_dark;
@ -2196,7 +2199,7 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
@Override
public int getMenuItemId() {
Integer action = AV_DEFAULT_ACTION.get();
Integer action = defaultActionSetting.get();
switch (action) {
case AV_DEFAULT_ACTION_AUDIO:
return AV_WIDGET_STATE_AUDIO;
@ -2226,19 +2229,14 @@ public class AudioVideoNotesPlugin extends OsmandPlugin {
@Override
public void changeState(int stateId) {
switch (stateId) {
case AV_WIDGET_STATE_AUDIO:
AV_DEFAULT_ACTION.set(AV_DEFAULT_ACTION_AUDIO);
break;
case AV_WIDGET_STATE_VIDEO:
AV_DEFAULT_ACTION.set(AV_DEFAULT_ACTION_VIDEO);
break;
case AV_WIDGET_STATE_PHOTO:
AV_DEFAULT_ACTION.set(AV_DEFAULT_ACTION_TAKEPICTURE);
break;
default:
AV_DEFAULT_ACTION.set(AV_DEFAULT_ACTION_CHOOSE);
break;
if (stateId == AV_WIDGET_STATE_AUDIO) {
defaultActionSetting.set(AV_DEFAULT_ACTION_AUDIO);
} else if (stateId == AV_WIDGET_STATE_VIDEO) {
defaultActionSetting.set(AV_DEFAULT_ACTION_VIDEO);
} else if (stateId == AV_WIDGET_STATE_PHOTO) {
defaultActionSetting.set(AV_DEFAULT_ACTION_TAKEPICTURE);
} else {
defaultActionSetting.set(AV_DEFAULT_ACTION_CHOOSE);
}
}
}

View file

@ -221,18 +221,13 @@ public class TerrainFragment extends BaseOsmAndFragment implements View.OnClickL
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.switch_compat:
onSwitchClick();
break;
case R.id.left_button:
setupTerrainMode(HILLSHADE);
break;
case R.id.right_button:
setupTerrainMode(SLOPE);
break;
default:
break;
int id = view.getId();
if (id == R.id.switch_compat) {
onSwitchClick();
} else if (id == R.id.left_button) {
setupTerrainMode(HILLSHADE);
} else if (id == R.id.right_button) {
setupTerrainMode(SLOPE);
}
}

View file

@ -191,13 +191,13 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
private boolean wasZoomInMultiTouch;
private float elevationAngle;
public OsmandMapTileView(MapActivity activity, int w, int h) {
public OsmandMapTileView(Activity activity, int w, int h) {
this.activity = activity;
init(activity, w, h);
}
// ///////////////////////////// INITIALIZING UI PART ///////////////////////////////////
public void init(final MapActivity ctx, int w, int h) {
public void init(final Activity ctx, int w, int h) {
application = (OsmandApplication) ctx.getApplicationContext();
settings = application.getSettings();
@ -256,7 +256,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
if (isZoomingAllowed(getZoom(), -1.1f)) {
getAnimatedDraggingThread().startZooming(getZoom() - 1, currentViewport.getZoomFloatPart(), false);
if (wasMapLinkedBeforeGesture) {
ctx.getMapViewTrackingUtilities().setMapLinkedToLocation(true);
application.getMapViewTrackingUtilities().setMapLinkedToLocation(true);
}
}
}
@ -1318,7 +1318,9 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
angle = 90f;
}
this.elevationAngle = angle;
((MapActivity) activity).setMapElevation(angle);
if (activity instanceof MapActivity) {
((MapActivity) activity).setMapElevation(angle);
}
}
private boolean isZoomingAllowed(int baseZoom, float dz) {
@ -1341,7 +1343,7 @@ public class OsmandMapTileView implements IMapDownloaderCallback {
@Override
public boolean onDown(MotionEvent e) {
// Facilitates better map re-linking for two finger tap zoom out
wasMapLinkedBeforeGesture = ((MapActivity) activity).getMapViewTrackingUtilities().isMapLinkedToLocation();
wasMapLinkedBeforeGesture = application.getMapViewTrackingUtilities().isMapLinkedToLocation();
return false;
}