@@ -2,23 +2,25 @@

## Mac OS

If you're running Mac OS, download the latest [RhoStudio for Macintosh](http://rhomobile.com/rhostudio-mac). This contains the [Ruby stack](http://www.ruby-lang.org/en/), [Redis](http://redis.io/), [RhoConnect](/rhoconnect/introduction) and [Rhodes](/rhodes/introduction).
If you're running Mac OS, download the latest [Motorola RhoMobile Suite Installer for Macintosh](http://rhomobile.com/rhostudio-mac). This contains [Redis](http://redis.io/), [RhoConnect](/rhoconnect/introduction) and [Rhodes](/rhodes/introduction).

Click on the RhoStudioInstaller for Mac download file to open it. You will get a window similar to this:
Mac OS has [Ruby](http://www.ruby-lang.org/en/) installed. It is recommended that you install [Ruby Version Manager](https://rvm.io//) and install Ruby version 1.9.3.

<img src="http://rhodocs.s3.amazonaws.com/rhodes-devel/rhostudio-mac-install.png" alt="RhoStudioInstaller Mac" />
Click on the RhoMobileSuiteInstaller for Mac download file to open it. You will get a window similar to this:

Run the install gems script appropriate for you. You can run "Install gems." If you have Ruby Version Manager, you can run "Install gems on rvm." A terminal window will open; wait for the gems install process to complete.
<img src="http://rhodocs.s3.amazonaws.com/rhodes-devel/rhostudio-mac-install.png" alt="RhoStudioInstaller Mac" />

Then drag RhoStudio to the Applications folder.
Run the install gems script appropriate for you. If you have Ruby Version Manager, you can run "Install gems on rvm." A terminal window will open; wait for the gems install process to complete.

You can also install Rhodes without RhoStudio by [installing Ruby and the Rhodes gem](/rhodes/install#rhodes-gem-for-linux-and-non-rhostudio).
Then drag Motorola RhoStudio to the Applications folder.

## Windows

If you're running Windows, download the latest [RhoStudio for Windows](http://rhomobile.com/rhostudio-windows). This installs the [Ruby stack](http://www.ruby-lang.org/en/), [Redis](http://redis.io/), [RhoConnect](/rhoconnect/introduction) and [Rhodes](/rhodes/introduction).
If you're running Windows, download and run the latest [Motorola RhoMobile Suite Installer for Windows](http://rhomobile.com/rhostudio-windows) and run it. This installs the [Ruby stack](http://www.ruby-lang.org/en/), [Redis](http://redis.io/), [RhoConnect](/rhoconnect/introduction) and [Rhodes](/rhodes/introduction).

If you are running Windows 64-bit, you need to [install Ruby and the Rhodes gem](/rhodes/install#rhodes-gem-for-linux-and-non-rhostudio). If you also want RhoStudio, you need to have 64-bit Eclipse, and then you [install RhoStudio as a plugin for Eclipse](/rhodes/rhostudio-eclipse).
If you are running Windows 64-bit, you need to use 32-bit Java when you run RhoStudio. You can include the 32-bit Java in the PATH, or you can run RhoStudio with a link to 32-bit Java:

C:\RhoStudio\eclipse\RhoStudio.exe -vm "<32-bit java path>\bin\javaw.exe"

Once the installer has completed, and you have installed the Java Development Kit, you can skip to the [Setup Rhodes section](#setup-rhodes).

@@ -38,28 +40,26 @@ On Windows installs for RhoMobile, go to RhoStudio Preferences (Windows -> Prefe

On Mac OS, the path to the JDK is automatically set once Java is installed.

For non-RhoStudio installations, set the JDK path on the JAVA_HOME variable in your PATH.

## Rhodes Gem for Linux and non-RhoStudio
For Linux and for Rhodes installs from the command line, set the JDK path in JAVA_HOME and PATH.

For Linux installations, and for Windows or Mac OS installations that are not using RhoStudio, you need to install the Rhodes gem. Download and install:
## Installing Rhodes from the Command Line

1. [Ruby v1.8.7](http://www.ruby-lang.org/en/downloads/) (On Windows, [RubyInstaller](http://rubyinstaller.org) is a convenient way to install Ruby.)
To install Rhodes on Linux, and to install Rhodes on Windows or Mac OS using the command line (this does not install RhoStudio), you need to install the Rhodes gem. Download and install:

2. [RubyGems](http://rubygems.org/pages/download) (RubyGems offers a .tgz, a .zip, and a .gem download. You want the .zip.) NOTE: Windows doesn't come with the necessary build tools to install gems ('make', for example). There are various ways to get these tools, but the GnuWin32 project at http://gnuwin32.sourceforge.net/ provides the tools, and can be conveniently installed via the GetGnuWin32 installer at http://sourceforge.net/projects/getgnuwin32/files/.
1. [Ruby v1.9.3](http://www.ruby-lang.org/en/downloads/) (On Windows, [RubyInstaller](http://rubyinstaller.org) is a convenient way to install Ruby; you should check "Add Ruby executables to your PATH" and "Associate .rb and .rbw files with this Ruby installation".)

3. Install the Rhode Gem.

Run this command to install.
2. Install the Rhodes Gem. Run this command to install.

:::term
$ [sudo] gem install rhodes

NOTE: If you get any `no such file to load -- something` messages while running the rake tasks or rhodes commands, this can usually be resolved by putting "sudo" in front of the command, as in `sudo gem install something`.

RhoSimulator, which comes with RhoStudio for Mac and Windows, does not work with Linux.
NOTE: Windows doesn't come with the necessary build tools to install gems ('make', for example). There are various ways to get these tools, but the GnuWin32 project at http://gnuwin32.sourceforge.net/ provides the tools, and can be installed via the GetGnuWin32 installer at http://sourceforge.net/projects/getgnuwin32/files/. You should follow the GetGnuWin32 instructions carefully.

You can [install RhoStudio as a plugin for Eclipse](rhostudio-eclipse) if you are not using RhoStudio for Macintosh or RhoStudio for Windows.
You can [install RhoStudio as a plugin for Eclipse](rhostudio-eclipse).

RhoSimulator, which comes with RhoStudio for Mac and Windows, does not work with Linux.

## Setup Rhodes

@@ -8,19 +8,22 @@ The [Tutorial](tutorial) describes how to install Rhodes and build your apps. Th

## Supported Operating Systems
### BlackBerry
BlackBerry 4.6, 4.7, 5.0, 6.0
BlackBerry 4.6, 4.7, 5.0, 6.0, 7.0

NOTE: 4.2 and 4.5 are supported but database access is very slow on these devices.

### Windows Mobile
Windows Mobile 6.1 Professional, 6.0 Standard
Windows Mobile 6.x Professional, 6.0 Standard

### Android
Android 1.6 and greater
Android 2.1 and greater

### iPhone
All versions of iPhone 3.0 or greater, iPad

### Windows Phone 7
Latest Windows Phone devices

## Rhodes Application

A Rhodes application is a web application that runs locally on your mobile device. It is implemented with the standard MVC architecture:
@@ -444,13 +444,12 @@ Calls `find` with a limit on the # of records. This emulates rails' classic pag
:order => 'name'
) #=> you can have :conditions and :order as well

### `sync(callback = nil, callback_data = "", show_status_popup = nil, query_params = "")`
### `sync(callback, callback_data, show_status_popup, query_params)`
Start the sync process for a model. If the callback is set, `SyncEngine.set_notification` is called before `SyncEngine.dosync`.
query_params will pass to sync server
query_params (this is optional) will pass to sync server. The query_params value must be URL encoded. In this example, the value for @params["sku"] -- the value of the sku -- must be URL encoded.

:::ruby
Account.sync( url_for(:action => :sync_callback) )
Account.sync( url_for(:action => :sync_callback), "", false, "param1=123&param2=abc" )
Product.sync( url_for(:action => :sync_callback), "", false, "query=#{@params["sku"]}" )

### `set_notification(url, params = nil)`
Set a notification to be called when the sync is complete for this model. This is useful for example if you want to refresh the current list page or display an alert when new data is synchronized. See the [sync notification docs](/rhodes/synchronization#notifications) for more information.
@@ -567,6 +566,9 @@ Or multiple declarations:

**NOTE: After a new product is created, the `:product_id` for the `Customer` records will be updated to the new value.**

If you are planning to use bulk sync feature for your associated models, then you should take into consideration
corresponding support on RhoConnect server side. See [RhoConnect Bulk Sync associations](/rhoconnect/bulk-sync#bulk-sync-associations).

## Freezed models
If you want to limit model attributes by specific list - you can 'freeze' model:

@@ -1,15 +1,15 @@
Installing RhoStudio as an Eclipse Plugin
==============

RhoStudio, which facilitates development of native smartphone applications, can be installed into Eclipse for developers not using RhoStudio for Macintosh or RhoStudio for Windows.
RhoStudio, which facilitates development of native smartphone applications, can be installed into Eclipse as a plug-in.

Prerequisites
----------------
You need to have installed:

* Java Runtime Environment, minimum of Java 5 JRE or JDK.
* [Rhodes gem](install#rhodes-gem-for-linux-and-non-rhostudio).
* For RhoConnect, you also need the [RhoConnect gem](/rhoconnect/install#rhoconnect-gem-for-linux-and-non-rhostudio).
* [Rhodes gem](/install#installing-rhodes-from-the-command-line).
* For RhoConnect, you also need the [RhoConnect gem](/rhoconnect/install#installing-rhoconnect-from-the-command-line).

Checking the Eclipse Installation
----------------
@@ -4,7 +4,7 @@ RhoSimulator allows to [run](#run-application-in-rhosimulator) Rhodes applicatio

## Install RhoSimulator

If you have [Rhodes gem](install#rhodes-gem-for-linux-and-non-rhostudio), then RhoSimulator is installed already.
If you have [Rhodes gem](/install#installing-rhodes-from-the-command-line), then RhoSimulator is installed already.

If you would like to run RhoSimulator without Rhodes gem, download [Windows](http://rhosimulator.s3.amazonaws.com/RhoSimulator.zip) or
[Mac OS X](http://rhosimulator.s3.amazonaws.com/RhoSimulator.tbz2) version, extract it and specify path to `rhosimulator.exe` or `RhoSimulator.app` respectively at `rhodes/rhobuild.yml`:
@@ -144,8 +144,19 @@ These parameters are included in all notifications.
* `@params["cumulative_count"]` - Number of records the `SyncEngine` has processed so far for this source.

#### "in_progress" - bulk sync
* `@params["bulk_status"]` - The state of the bulk sync process: "start", "download", "change_db".

* `@params["bulk_status"]` - The state of the bulk sync process:

"start": when bulk sync start and when specific partition is start syncing

"download": when client start downloading database from server

"change_db": when client start applying new database

"ok": when sync of partition finished without error

"complete": when bulk sync finished for all partitions without errors

* `@params["partition"]` - Current bulk sync partition.

#### "error"
* `@params["error_code"]` - HTTP response code of the RhoConnect server error: 401, 500, 404, etc.
@@ -94,6 +94,8 @@ Call the RhoLog error or info methods from a method in your Rhodes app:
RhoLog.error("Some Category", "Some message")
end

Additionally all common ruby output routines (like puts, print) are redirected to rhodes log with INFO level.

In rholog.txt the lines appear as follows:

<Timestamp> <category> | <message>
@@ -128,6 +130,6 @@ See [Login/Logout Manager]() as an example.

## Debugging

You can use the [RhoStudio debugger](rhostudio.tutorial#using-the-debugger) to debug your Rhodes app.
You can use the [RhoStudio debugger](/rhostudio.tutorial#using-the-debugger) to debug your Rhodes app.


@@ -9,6 +9,14 @@
#Only because iphone sim doesn work if you run it with sudo
chmod_R 0777, File.dirname(__FILE__) + "/.."

File.chmod 0755, File.dirname(__FILE__) + "/../bin/get-rhodes-info"
File.chmod 0755, File.dirname(__FILE__) + "/../bin/migrate-rhodes-app"
File.chmod 0755, File.dirname(__FILE__) + "/../bin/rhodes"
File.chmod 0755, File.dirname(__FILE__) + "/../bin/rhodes-setup"
File.chmod 0755, File.dirname(__FILE__) + "/../bin/rhogen"
File.chmod 0755, File.dirname(__FILE__) + "/../bin/set-rhodes-sdk"
File.chmod 0755, File.dirname(__FILE__) + "/../bin/upgrade-rhodes-app"

#This is the hack, we make all the things to make it look like an extension has compiled

File.open('Makefile', 'w') { |f| f.write "all:\n\ninstall:\n\n" }
@@ -172,9 +172,9 @@ def self.run_spec_app(platform,appname)
reset_spec_server(platform) if appname =~ /phone_spec/

rhobuildyml = File.join(basedir,'rhobuild.yml')
rhobuild = YAML::load_file(rhobuildyml)
rhobuild['env']['app'] = app_expanded_path(appname)
File.open(rhobuildyml,'w') {|f| f.write rhobuild.to_yaml}
#rhobuild = YAML::load_file(rhobuildyml)
#rhobuild['env']['app'] = app_expanded_path(appname)
#File.open(rhobuildyml,'w') {|f| f.write rhobuild.to_yaml}
$app_path = File.expand_path(File.join(basedir,'spec',appname))
$app_config = Jake.config(File.open(File.join($app_path, "build.yml")))
$config = Jake.config(File.open(rhobuildyml,'r'))
@@ -497,7 +497,7 @@ def self.modify_file_if_content_changed(file_name, f)
old_content = File.exists?(file_name) ? File.read(file_name) : ""

if old_content != content
puts "Modify #{file_name}"
puts "!!!MODIFY #{file_name}"
File.open(file_name, "w"){|file| file.write(content)}
end

@@ -609,7 +609,7 @@ def self.run_rho_log_server(app_path)
puts "EXC: #{e}"
end

system("START rake run:webrickrhologserver[#{app_path}]")
system("START rake run:webrickrhologserver[\"#{app_path}\"]")
end

end
@@ -14,28 +14,28 @@ def build_extension(name, arch, src_files)
#Dir.glob("*.c").each do |f|
src_files.each do |f|
objname = File.join( $tempdir, File.basename( f.gsub(/\.c$/, '.o') ) )
objects << objname
objects << ('"'+objname+'"')

args = []
args << "-I."
args << "-I#{$rootdir}/platform/shared/ruby/include"
args << "-I#{$rootdir}/platform/shared"
args << "-I\"#{$rootdir}/platform/shared/ruby/include\""
args << "-I\"#{$rootdir}/platform/shared\""

args << "-I#{$std_includes}" unless $std_includes.nil?
args << "-I\"#{$std_includes}\"" unless $std_includes.nil?
args << "-D__NEW__" if use_own_stlport
args << "-I#{$stlport_includes}" if use_own_stlport
args << "-I\"#{$stlport_includes}\"" if use_own_stlport

args << "-I#{$rootdir}/platform/shared/ruby/android"
args << "-I#{$rootdir}/platform/shared/ruby/generated"
args << "-I#{$rootdir}/platform/android/Rhodes/jni/include"
args << "-I\"#{$rootdir}/platform/shared/ruby/android\""
args << "-I\"#{$rootdir}/platform/shared/ruby/generated\""
args << "-I\"#{$rootdir}/platform/android/Rhodes/jni/include\""

cc_compile f, $tempdir, args or exit 1

end

mkdir_p $targetdir unless File.exist? $targetdir

cc_ar File.join( $targetdir, 'lib' + name + '.a' ), Dir.glob($tempdir + "/**/*.o") or exit 1
cc_ar ('"'+File.join( $targetdir, 'lib' + name + '.a' )+'"'), Dir.glob($tempdir + "/**/*.o").collect{|x| '"'+x+'"'} or exit 1

end

@@ -67,44 +67,37 @@ private enum State {

@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.auto_focus:
if (message.what == R.id.auto_focus) {
//Log.d(TAG, "Got auto-focus message");
// When one auto focus pass finishes, start another. This is the closest thing to
// continuous AF. It does seem to hunt a bit, but I'm not sure what else to do.
if (state == State.PREVIEW) {
CameraManager.get().requestAutoFocus(this, R.id.auto_focus);
}
break;
case R.id.restart_preview:
} else if (message.what == R.id.restart_preview) {
Log.d(TAG, "Got restart preview message");
restartPreviewAndDecode();
break;
case R.id.decode_succeeded:
} else if (message.what == R.id.decode_succeeded) {
Log.d(TAG, "Got decode succeeded message");
state = State.SUCCESS;
Bundle bundle = message.getData();
Bitmap barcode = bundle == null ? null :
(Bitmap) bundle.getParcelable(DecodeThread.BARCODE_BITMAP);
activity.handleDecode((Result) message.obj, barcode);
break;
case R.id.decode_failed:
} else if (message.what == R.id.decode_failed) {
// We're decoding as fast as possible, so when one decode fails, start another.
state = State.PREVIEW;
CameraManager.get().requestPreviewFrame(decodeThread.getHandler(), R.id.decode);
break;
case R.id.return_scan_result:
} else if (message.what == R.id.return_scan_result) {
Log.d(TAG, "Got return scan result message");
activity.setResult(Activity.RESULT_OK, (Intent) message.obj);
activity.finish();
break;
case R.id.launch_product_query:
} else if (message.what == R.id.launch_product_query) {
Log.d(TAG, "Got product query message");
String url = (String) message.obj;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
activity.startActivity(intent);
break;
}
}

@@ -49,14 +49,10 @@ final class DecodeHandler extends Handler {

@Override
public void handleMessage(Message message) {
switch (message.what) {
case R.id.decode:
//Log.d(TAG, "Got decode message");
if (message.what == R.id.decode) {
decode((byte[]) message.obj, message.arg1, message.arg2);
break;
case R.id.quit:
} else if (message.what == R.id.quit) {
Looper.myLooper().quit();
break;
}
}

@@ -6,42 +6,44 @@ def build_extension(name, arch)

Dir.glob("*.c").each do |f|
objname = File.join( $tempdir, File.basename( f.gsub(/\.c$/, '.o') ) )
objects << objname
objects << ('"'+objname+'"')

args = []
args << "-I."
args << "-I#{$rhoroot}/lib/extensions/digest/ext"
args << "-I#{$rhoroot}/platform/shared/ruby/include"
args << "-I#{$rhoroot}/platform/shared"
args << "-I\"#{$rhoroot}/lib/extensions/digest/ext\""
args << "-I\"#{$rhoroot}/platform/shared/ruby/include\""
args << "-I\"#{$rhoroot}/platform/shared\""
args << "-I\"#{$rhoroot}/platform/shared/common\""

if ENV['RHO_PLATFORM'] == 'android'
args << "-I#{$rhoroot}/platform/shared/ruby/android"
args << "-I#{$rhoroot}/platform/shared/ruby/generated"
args << "-I\"#{$rhoroot}/platform/shared/ruby/android\""
args << "-I\"#{$rhoroot}/platform/shared/ruby/generated\""
cc_compile f, $tempdir, args or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args << "-I#{$rhoroot}/platform/shared/ruby/iphone"
args << "-I\"#{$rhoroot}/platform/shared/ruby/iphone\""
args << "-D_XOPEN_SOURCE"
args << "-D_DARWIN_C_SOURCE"
args << "-isysroot #{$sdkroot}"
args << "-isysroot \"#{$sdkroot}\""
args << "-fno-common"
args << "-arch #{arch}"
args << "-O2"
args << "-o #{objname}"
args << "-o \"#{objname}\""
args << "-c"
args << f
cmdline = $gccbin + ' ' + args.join(' ')
puts cmdline
puts `#{cmdline}`
exit unless $? == 0


end
end

mkdir_p $targetdir unless File.exist? $targetdir

if ENV['RHO_PLATFORM'] == 'android'
cc_ar File.join( $targetdir, 'lib' + name + '.a' ), Dir.glob($tempdir + "/**/*.o") or exit 1
cc_ar ('"'+File.join( $targetdir, 'lib' + name + '.a' )+'"'), Dir.glob($tempdir + "/**/*.o").collect{|x| '"'+x+'"'} or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args = []
@@ -6,28 +6,29 @@ def build_extension(name, arch)

Dir.glob("*.c").each do |f|
objname = File.join( $tempdir, File.basename( f.gsub(/\.c$/, '.o') ) )
objects << objname
objects << ('"'+objname+'"')

args = []
args << "-I."
args << "-I#{$rhoroot}/lib/extensions/digest/ext"
args << "-I#{$rhoroot}/platform/shared/ruby/include"
args << "-I#{$rhoroot}/platform/shared"
args << "-I\"#{$rhoroot}/lib/extensions/digest/ext\""
args << "-I\"#{$rhoroot}/platform/shared/ruby/include\""
args << "-I\"#{$rhoroot}/platform/shared\""
args << "-I\"#{$rhoroot}/platform/shared/common\""

if ENV['RHO_PLATFORM'] == 'android'
args << "-I#{$rhoroot}/platform/shared/ruby/android"
args << "-I#{$rhoroot}/platform/shared/ruby/generated"
args << "-I\"#{$rhoroot}/platform/shared/ruby/android\""
args << "-I\"#{$rhoroot}/platform/shared/ruby/generated\""
cc_compile f, $tempdir, args or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args << "-I#{$rhoroot}/platform/shared/ruby/iphone"
args << "-I\"#{$rhoroot}/platform/shared/ruby/iphone\""
args << "-D_XOPEN_SOURCE"
args << "-D_DARWIN_C_SOURCE"
args << "-isysroot #{$sdkroot}"
args << "-isysroot \"#{$sdkroot}\""
args << "-fno-common"
args << "-arch #{arch}"
args << "-O2"
args << "-o #{objname}"
args << "-o \"#{objname}\""
args << "-c"
args << f
cmdline = $gccbin + ' ' + args.join(' ')
@@ -41,7 +42,7 @@ def build_extension(name, arch)
mkdir_p $targetdir unless File.exist? $targetdir

if ENV['RHO_PLATFORM'] == 'android'
cc_ar File.join( $targetdir, 'lib' + name + '.a' ), Dir.glob($tempdir + "/**/*.o") or exit 1
cc_ar ('"'+File.join( $targetdir, 'lib' + name + '.a' )+'"'), Dir.glob($tempdir + "/**/*.o").collect{|x| '"'+x+'"'} or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args = []
@@ -6,27 +6,28 @@ def build_extension(name, arch)

Dir.glob("*.c").each do |f|
objname = File.join( $tempdir, File.basename( f.gsub(/\.c$/, '.o') ) )
objects << objname
objects << ('"'+objname+'"')

args = []
args << "-I."
args << "-I#{$rootdir}/platform/shared/ruby/include"
args << "-I#{$rootdir}/platform/shared"
args << "-I\"#{$rootdir}/platform/shared/ruby/include\""
args << "-I\"#{$rootdir}/platform/shared\""
args << "-I\"#{$rootdir}/platform/shared/common\""

if ENV['RHO_PLATFORM'] == 'android'
args << "-I#{$rootdir}/platform/shared/ruby/android"
args << "-I#{$rootdir}/platform/shared/ruby/generated"
args << "-I\"#{$rootdir}/platform/shared/ruby/android\""
args << "-I\"#{$rootdir}/platform/shared/ruby/generated\""
cc_compile f, $tempdir, args or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args << "-I#{$rootdir}/platform/shared/ruby/iphone"
args << "-I\"#{$rootdir}/platform/shared/ruby/iphone\""
args << "-D_XOPEN_SOURCE"
args << "-D_DARWIN_C_SOURCE"
args << "-isysroot #{$sdkroot}"
args << "-isysroot \"#{$sdkroot}\""
args << "-fno-common"
args << "-arch #{arch}"
args << "-O2"
args << "-o #{objname}"
args << "-o \"#{objname}\""
args << "-c"
args << f
cmdline = $gccbin + ' ' + args.join(' ')
@@ -40,7 +41,7 @@ def build_extension(name, arch)
mkdir_p $targetdir unless File.exist? $targetdir

if ENV['RHO_PLATFORM'] == 'android'
cc_ar File.join( $targetdir, 'lib' + name + '.a' ), Dir.glob($tempdir + "/**/*.o") or exit 1
cc_ar ('"'+File.join( $targetdir, 'lib' + name + '.a' )+'"'), Dir.glob($tempdir + "/**/*.o").collect{|x| '"'+x+'"'} or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args = []
@@ -6,41 +6,42 @@ def build_extension(name, arch)

Dir.glob("*.c").each do |f|
objname = File.join( $tempdir, File.basename( f.gsub(/\.c$/, '.o') ) )
objects << objname
objects << ('"'+objname+'"')

args = []
args << "-I."
args << "-I#{$rootdir}/platform/shared/ruby/include"
args << "-I#{$rootdir}/platform/shared"
args << "-I\"#{$rootdir}/platform/shared/ruby/include\""
args << "-I\"#{$rootdir}/platform/shared\""

if ENV['RHO_PLATFORM'] == 'android'
args << "-I#{$rootdir}/platform/shared/ruby/android"
args << "-I#{$rootdir}/platform/shared/ruby/generated"
args << "-I\"#{$rootdir}/platform/shared/ruby/android\""
args << "-I\"#{$rootdir}/platform/shared/ruby/generated\""
cc_compile f, $tempdir, args or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args << "-I#{$rootdir}/platform/shared/ruby/iphone"
args << "-I\"#{$rootdir}/platform/shared/ruby/iphone\""
args << "-D_XOPEN_SOURCE"
args << "-D_DARWIN_C_SOURCE"
args << "-isysroot #{$sdkroot}"
args << "-isysroot \"#{$sdkroot}\""
args << "-fno-common"
args << "-arch #{arch}"
args << "-O2"
args << "-o #{objname}"
args << "-o \"#{objname}\""
args << "-c"
args << f
cmdline = $gccbin + ' ' + args.join(' ')
puts cmdline
puts `#{cmdline}`
exit unless $? == 0


end
end

mkdir_p $targetdir unless File.exist? $targetdir

if ENV['RHO_PLATFORM'] == 'android'
cc_ar File.join( $targetdir, 'lib' + name + '.a' ), Dir.glob($tempdir + "/**/*.o") or exit 1
cc_ar ('"'+File.join( $targetdir, 'lib' + name + '.a' )+'"'), Dir.glob($tempdir + "/**/*.o").collect{|x| '"'+x+'"'} or exit 1

elsif (ENV['RHO_PLATFORM'] == 'iphone') or (ENV['RHO_PLATFORM'] == 'osx')
args = []
@@ -15,29 +15,29 @@ def build_extension(name, arch, src_files)
#Dir.glob("*.c").each do |f|
src_files.each do |f|
objname = File.join( $tempdir, File.basename( f.gsub(/\.c$/, '.o') ) )
objects << objname
objects << ('"'+objname+'"')

args = []
args << "-I."
args << "-I#{$rootdir}/platform/android/Rhodes/jni/include"
args << "-I#{$rootdir}/platform/shared/ruby/include"
args << "-I#{$rootdir}/platform/shared"
args << "-I#{$rootdir}/platform/shared/common"
args << "-I\"#{$rootdir}/platform/shared/ruby/include\""
args << "-I\"#{$rootdir}/platform/shared\""
args << "-I\"#{$rootdir}/platform/shared/common\""

args << "-I#{$std_includes}" unless $std_includes.nil?
args << "-I\"#{$std_includes}\"" unless $std_includes.nil?
args << "-D__NEW__" if use_own_stlport
args << "-I#{$stlport_includes}" if use_own_stlport

args << "-I#{$rootdir}/platform/shared/ruby/android"
args << "-I#{$rootdir}/platform/shared/ruby/generated"
args << "-I\"#{$stlport_includes}\"" if use_own_stlport

args << "-I\"#{$rootdir}/platform/shared/ruby/android\""
args << "-I\"#{$rootdir}/platform/shared/ruby/generated\""
args << "-I\"#{$rootdir}/platform/android/Rhodes/jni/include\""

cc_compile f, $tempdir, args or exit 1

end

mkdir_p $targetdir unless File.exist? $targetdir

cc_ar File.join( $targetdir, 'lib' + name + '.a' ), Dir.glob($tempdir + "/**/*.o") or exit 1
cc_ar ('"'+File.join( $targetdir, 'lib' + name + '.a' )+'"'), Dir.glob($tempdir + "/**/*.o").collect{|x| '"'+x+'"'} or exit 1

end

@@ -37,12 +37,14 @@
import android.util.Log;

import com.rhomobile.rhodes.RhodesActivity;
import com.rhomobile.rhodes.RhodesActivityListener;
import com.rhomobile.rhodes.RhodesService;
import com.rhomobile.rhodes.extmanager.IRhoExtManager;;
import com.rhomobile.rhodes.extmanager.IRhoListener;
import com.rhomobile.rhodes.extmanager.RhoExtManager;;
import com.rhomobile.rhodes.util.Utils;
import com.rhomobile.rhodes.util.PerformOnUiThread;

public class Nfc implements RhodesActivityListener {
public class Nfc implements IRhoListener {

private static final String TAG = Nfc.class.getSimpleName();

@@ -118,9 +120,6 @@ public static void loge(String msg) {
}

public static Nfc getInstance() {
if (ourInstance == null) {
ourInstance = new Nfc();
}
return ourInstance;
}

@@ -200,8 +199,9 @@ public void onCreate(RhodesActivity activity, Intent intent) {
}

@Override
public void onRhodesActivityStartup(RhodesActivity activity) {
activity.addRhodesActivityListener(getInstance());
public void onCreateApplication(IRhoExtManager extManager) {
ourInstance = this;
extManager.addRhoListener(this);
}

@Override
@@ -2094,26 +2094,26 @@ SWIG_ruby_failed(void)


/*@SWIG:/usr/local/share/swig/2.0.4/ruby/rubyprimtypes.swg,19,%ruby_aux_method@*/
SWIGINTERN VALUE SWIG_AUX_NUM2LONG(VALUE *args)
SWIGINTERN VALUE SWIG_AUX_NUM2LL(VALUE *args)
{
VALUE obj = args[0];
VALUE type = TYPE(obj);
long *res = (long *)(args[1]);
*res = type == T_FIXNUM ? NUM2LONG(obj) : rb_big2long(obj);
long long *res = (long long *)(args[1]);
*res = type == T_FIXNUM ? NUM2LL(obj) : rb_big2ll(obj);
return obj;
}
/*@SWIG@*/

SWIGINTERN int
SWIG_AsVal_long (VALUE obj, long* val)
SWIG_AsVal_long_SS_long (VALUE obj, long long *val)
{
VALUE type = TYPE(obj);
if ((type == T_FIXNUM) || (type == T_BIGNUM)) {
long v;
long long v;
VALUE a[2];
a[0] = obj;
a[1] = (VALUE)(&v);
if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2LONG), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
if (rb_rescue(RUBY_METHOD_FUNC(SWIG_AUX_NUM2LL), (VALUE)a, RUBY_METHOD_FUNC(SWIG_ruby_failed), 0) != Qnil) {
if (val) *val = v;
return SWIG_OK;
}
@@ -2125,8 +2125,8 @@ SWIG_AsVal_long (VALUE obj, long* val)
SWIGINTERN int
SWIG_AsVal_int (VALUE obj, int *val)
{
long v;
int res = SWIG_AsVal_long (obj, &v);
long long v = 0;
int res = SWIG_AsVal_long_SS_long (obj, &v);
if (SWIG_IsOK(res)) {
if ((v < INT_MIN || v > INT_MAX)) {
return SWIG_OverflowError;
@@ -2141,10 +2141,17 @@ SWIG_AsVal_int (VALUE obj, int *val)
#define SWIG_From_long LONG2NUM


SWIGINTERNINLINE VALUE
SWIG_From_long_SS_long (long long value)
{
return LL2NUM(value);
}


SWIGINTERNINLINE VALUE
SWIG_From_int (int value)
{
return SWIG_From_long (value);
return SWIG_From_long_SS_long (value);
}

SWIGINTERN VALUE
@@ -1254,6 +1254,12 @@ def self.on_sync_create_error( src_name, objects, action )
Object.const_get(src_name).on_sync_create_error(objects, action)
end

def self.push_changes( src_name )
raise ArgumentError, 'push_changes src_name should be string' unless src_name.is_a?(String)

Object.const_get(src_name).push_changes()
end

def self.on_sync_update_error( src_name, objects, action, rollback_data = nil )
raise ArgumentError, 'on_sync_update_error src_name should be string' unless src_name.is_a?(String)

@@ -1246,6 +1246,14 @@ def on_sync_update_error( objects, action, rollback_data = nil )
raise
end
end

def push_changes()
return unless is_sync_source()
nSrcID = get_source_id()
db = ::Rho::RHO.get_src_db(get_source_name)

db.insert_into_table('changed_values', {'update_type'=>'push_changes', 'source_id' => nSrcID } )
end

def on_sync_create_error( objects, action )
raise ArgumentError, 'on_sync_create_error action should be :delete or :recreate' unless action == :delete || action == :recreate
@@ -48,7 +48,7 @@ JavaVM *jvm();
void store_thr_jnienv(JNIEnv *env);

extern "C" {
void android_set_path(const rho::String& root, const rho::String& sqlite);
void android_set_path(const rho::String& root, const rho::String& sqlite, const rho::String& shared);
void android_setup(JNIEnv *env);
}

@@ -259,9 +259,9 @@ RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_file_RhoFileApi_updateStatTabl
}

RHO_GLOBAL void JNICALL Java_com_rhomobile_rhodes_file_RhoFileApi_nativeInitPath
(JNIEnv *env, jclass, jstring root_path, jstring sqlite_journals_path, jstring apk_path)
(JNIEnv *env, jclass, jstring root_path, jstring sqlite_journals_path, jstring apk_path, jstring shared_path)
{
android_set_path(rho_cast<std::string>(env, root_path), rho_cast<std::string>(env, sqlite_journals_path));
android_set_path(rho_cast<std::string>(env, root_path), rho_cast<std::string>(env, sqlite_journals_path), rho_cast<std::string>(env, shared_path));
g_apk_path = (apk_path != NULL) ? rho_cast<std::string>(env, apk_path) : std::string();
}

Large diffs are not rendered by default.

@@ -136,7 +136,7 @@ void* RhoNativeViewManager::getWebViewObject(int tab_index) {
JNIEnv *env = jnienv();
jclass cls = rho_find_class(env, "com/rhomobile/rhodes/nativeview/RhoNativeViewManager");
if (!cls) return null;
jmethodID mid = env->GetStaticMethodID( cls, "getWebViewObject", "(I)Landroid/webkit/WebView;");
jmethodID mid = env->GetStaticMethodID( cls, "getWebViewObject", "(I)Ljava/lang/Object;");
if (!mid) return null;
return env->CallStaticObjectMethod(cls, mid, tab_index);
}
@@ -33,6 +33,7 @@
#include "common/RhoStd.h"
#include "common/RhoConf.h"
#include "common/RhodesAppBase.h"
#include "common/app_build_capabilities.h"
#include "sqlite/sqlite3.h"
#include "logging/RhoLogConf.h"

@@ -42,19 +43,26 @@ static rho::common::CAutoPtr<rho::common::AndroidMemoryInfoCollector> s_memory_i

static rho::String s_root_path;
static rho::String s_sqlite_path;
static rho::String s_shared_path;

//--------------------------------------------------------------------------------------------------
RHO_GLOBAL void android_set_path(const rho::String& root, const rho::String& sqlite)
RHO_GLOBAL void android_set_path(const rho::String& root, const rho::String& sqlite, const rho::String& shared)
{
s_root_path = root;
s_sqlite_path = sqlite;
s_shared_path = shared;
}
//--------------------------------------------------------------------------------------------------
rho::String const &rho_root_path()
{
return s_root_path;
}
//--------------------------------------------------------------------------------------------------
rho::String const &rho_shared_path()
{
return s_shared_path;
}
//--------------------------------------------------------------------------------------------------
const char* rho_native_rhopath()
{
return rho_root_path().c_str();
@@ -167,7 +175,11 @@ RHO_GLOBAL void android_setup(JNIEnv *env)
sqlite3_temp_directory = (char*)s_sqlite_path.c_str();

// Init logconf
#ifdef APP_BUILD_CAPABILITY_SHARED_RUNTIME
rho_logconf_Init(rho_shared_path().c_str(), rho_native_rhopath(), "");
#else
rho_logconf_Init(rho_native_rhopath(), rho_native_rhopath(), "");
#endif

// Disable log to stdout as on android all stdout redirects to /dev/null
RHOCONF().setBool("LogToOutput", false, true);
@@ -82,14 +82,10 @@ RHO_GLOBAL void rho_signature_take(char* callback_url, rho_param* p)
RHO_GLOBAL void rho_signature_visible(bool visible, rho_param* p)
{
// check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
if (!rho_is_rho_elements_extension_can_be_used()) {
RAWLOG_ERROR("Rho::SignatureCapture.visible() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
return;
}
#endif
#endif

JNIEnv *env = jnienv();
jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
@@ -105,14 +101,10 @@ RHO_GLOBAL void rho_signature_visible(bool visible, rho_param* p)
RHO_GLOBAL void rho_signature_capture(const char* callback_url)
{
// check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
if (!rho_is_rho_elements_extension_can_be_used()) {
RAWLOG_ERROR("Rho::SignatureCapture.capture() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
return;
}
#endif
#endif

JNIEnv *env = jnienv();
jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
@@ -129,14 +121,10 @@ RHO_GLOBAL void rho_signature_capture(const char* callback_url)
RHO_GLOBAL void rho_signature_clear()
{
// check for RhoElements :
#ifndef APP_BUILD_CAPABILITY_MOTOROLA
#ifndef APP_BUILD_CAPABILITY_MOTOROLA_BROWSER
if (!rho_is_rho_elements_extension_can_be_used()) {
RAWLOG_ERROR("Rho::SignatureCapture.clear() is unavailable without RhoElements ! For more information go to http://www.motorolasolutions.com/rhoelements");
return;
}
#endif
#endif

JNIEnv *env = jnienv();
jclass cls = getJNIClass(RHODES_JAVA_CLASS_SIGNATURE);
@@ -27,19 +27,16 @@
package com.rhomobile.rhodes;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

import com.rhomobile.rhodes.bluetooth.RhoBluetoothManager;
import com.rhomobile.rhodes.camera.Camera;
import com.rhomobile.rhodes.extmanager.RhoExtManager;
import com.rhomobile.rhodes.file.RhoFileApi;
import com.rhomobile.rhodes.mainview.MainView;
import com.rhomobile.rhodes.mainview.SimpleMainView;
import com.rhomobile.rhodes.mainview.SplashScreen;
import com.rhomobile.rhodes.signature.Signature;
import com.rhomobile.rhodes.util.PerformOnUiThread;
import com.rhomobile.rhodes.util.Utils;
import com.rhomobile.rhodes.webview.GoogleWebView;
import com.rhomobile.rhodes.webview.IRhoWebView;

@@ -53,13 +50,13 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.AbsoluteLayout;

public class RhodesActivity extends BaseActivity implements SplashScreen.SplashScreenListener {

@@ -87,8 +84,6 @@ public long getUiThreadId() {
return uiThreadId;
}

private ArrayList<RhodesActivityListener> mListeners = null;

private boolean mIsForeground = false;
private boolean mIsInsideStartStop = false;

@@ -100,53 +95,16 @@ public boolean isInsideStartStop() {
return mIsInsideStartStop;
}

public void addRhodesActivityListener(RhodesActivityListener listener) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
}

public void removeRhodesActivityListener(RhodesActivityListener listener) {
mListeners.remove(listener);
}

public void processStartupListeners() {
int i;
for (i = 1; i < RhodesActivityStartupListeners.ourRunnableList.length; i++) {
String classname = RhodesActivityStartupListeners.ourRunnableList[i];
Class<? extends RhodesActivityListener> klass = null;
try {
klass = Class.forName(classname).asSubclass(RhodesActivityListener.class);
} catch (ClassNotFoundException e) {
Utils.platformLog("RhodesActivity", "processStartupListeners() : ClassNotFoundException for ["+classname+"]");
e.printStackTrace();
}
RhodesActivityListener listener = null;
try {
if (klass != null) {
listener = klass.newInstance();
}
} catch (InstantiationException e) {
Utils.platformLog("RhodesActivity", "processStartupListeners() : InstantiationException for ["+classname+"]");
e.printStackTrace();
} catch (IllegalAccessException e) {
Utils.platformLog("RhodesActivity", "processStartupListeners() : IllegalAccessException for ["+classname+"]");
e.printStackTrace();
}
if (listener != null) {
listener.onRhodesActivityStartup(this);
}
}
}

//public void removeRhodesActivityListener(IRhoListener listener) {
// mListeners.remove(listener);
//}

@Override
protected void onCreate(Bundle savedInstanceState) {
Logger.T(TAG, "onCreate");
super.onCreate(savedInstanceState);

mListeners = new ArrayList<RhodesActivityListener>();

Thread ct = Thread.currentThread();
//ct.setPriority(Thread.MAX_PRIORITY);
uiThreadId = ct.getId();
@@ -165,27 +123,46 @@ protected void onCreate(Bundle savedInstanceState) {

mHandler = new Handler();

Logger.T(TAG, "Creating splash screen");
mSplashScreen = new SplashScreen(this, createWebView(), this);
setMainView(mSplashScreen);

Signature.registerSignatureCaptureExtension();

processStartupListeners();
{
Iterator<RhodesActivityListener> iterator = mListeners.iterator();
while (iterator.hasNext()) {
iterator.next().onCreate(this, getIntent());
}
}
RhoExtManager.getImplementationInstance().onCreateActivity(this, getIntent());

notifyUiCreated();
RhodesApplication.stateChanged(RhodesApplication.UiState.MainActivityCreated);


if (!isPassMotoLicence()) {
Logger.E(TAG, "############################");
Logger.E(TAG, " ");
Logger.E(TAG, "ERROR: motorola_license is INVALID !");
Logger.E(TAG, " ");
Logger.E(TAG, "############################");
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setCancelable(true);
b.setOnCancelListener( new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
//RhodesService.exit();
}
});
AlertDialog securityAlert = b.create();
securityAlert.setMessage("Please provide RhoElements license key.");
securityAlert.setButton("OK", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface arg0, int arg1) {
//RhodesService.exit();
}

});
securityAlert.show();
return;
}
}

public IRhoWebView createWebView() {
IRhoWebView view = null;//new GoogleWebView(context);
IRhoWebView view = null;
if (Capabilities.WEBKIT_BROWSER_ENABLED) {
Logger.D(TAG, "Creating Motorola WebKIT view");
Logger.T(TAG, "Creating Motorola WebKIT view");
try {
Class<? extends IRhoWebView> viewClass = Class.forName("com.rhomobile.rhodes.webview.EkiohWebView").asSubclass(IRhoWebView.class);
if (Capabilities.MOTOROLA_BROWSER_ENABLED) {
@@ -200,7 +177,7 @@ public IRhoWebView createWebView() {
RhodesApplication.stop();
}
} else {
Logger.D(TAG, "Creating Google web view");
Logger.T(TAG, "Creating Google web view");
final GoogleWebView googleWebView = new GoogleWebView(this);
view = googleWebView;
RhodesApplication.runWhen(RhodesApplication.AppState.AppStarted, new RhodesApplication.StateHandler(true) {
@@ -211,11 +188,17 @@ public void run()
}
});
}
AbsoluteLayout containerView = new AbsoluteLayout(this);
containerView.addView(view.getView(), new AbsoluteLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0));
view.setContainerView(containerView);

return view;
}

public MainView switchToSimpleMainView(MainView currentView) {
MainView view = new SimpleMainView(currentView.detachWebView());
IRhoWebView rhoWebView = currentView.detachWebView();
SimpleMainView view = new SimpleMainView(rhoWebView);
rhoWebView.setWebClient(this);
setMainView(view);
return view;
}
@@ -267,51 +250,35 @@ protected void onNewIntent(Intent intent) {

handleStartParams(intent);

{
Iterator<RhodesActivityListener> iterator = mListeners.iterator();
while (iterator.hasNext()) {
iterator.next().onNewIntent(this, intent);
}
}
RhoExtManager.getImplementationInstance().onNewIntent(this, intent);
}

@Override
public void onStart() {
super.onStart();
@Override
public void onStart() {
super.onStart();

Logger.D(TAG, "onStart");
mIsInsideStartStop = true;

RhodesApplication.stateChanged(RhodesApplication.UiState.MainActivityStarted);

for(RhodesActivityListener listener: mListeners) {
listener.onStart(this);
}
}

@Override
public void onResume() {
RhoExtManager.getImplementationInstance().onStartActivity(this);
}

@Override
public void onResume() {
Logger.D(TAG, "onResume");
mIsForeground = true;
super.onResume();
{
Iterator<RhodesActivityListener> iterator = mListeners.iterator();
while (iterator.hasNext()) {
iterator.next().onResume(this);
}
}
}
mIsForeground = true;
super.onResume();

RhoExtManager.getImplementationInstance().onResumeActivity(this);
}

@Override
public void onPause()
{
mIsForeground = false;
{
Iterator<RhodesActivityListener> iterator = mListeners.iterator();
while (iterator.hasNext()) {
iterator.next().onPause(this);
}
}
mIsForeground = false;

RhoExtManager.getImplementationInstance().onPauseActivity(this);

super.onPause();
Logger.D(TAG, "onPause");
@@ -320,27 +287,25 @@ public void onPause()
}

@Override
public void onStop()
{
super.onStop();
public void onStop()
{
super.onStop();
Logger.D(TAG, "onStop");
for(RhodesActivityListener listener: mListeners) {
listener.onStop(this);
}

RhoExtManager.getImplementationInstance().onStopActivity(this);

mIsInsideStartStop = false;
}
@Override
public void onDestroy() {
}

@Override
public void onDestroy() {
Logger.D(TAG, "onDestroy");

for(RhodesActivityListener listener: mListeners) {
listener.onDestroy(this);
}

RhoExtManager.getImplementationInstance().onDestroyActivity(this);

sInstance = null;
super.onDestroy();
}
super.onDestroy();
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
@@ -386,13 +351,7 @@ public void onSplashScreenNavigateBack() {

@Override
protected Dialog onCreateDialog(int id/*, Bundle args*/) {
Dialog res = null;
for(RhodesActivityListener handler: mListeners) {
res = handler.onCreateDialog(this, id/*, args*/);
if(res != null)
break;
}
return res;
return RhoExtManager.getImplementationInstance().onCreateDialog(this, id);
}

@Deprecated
@@ -442,7 +401,7 @@ public void onServiceConnected(ComponentName name, IBinder service) {

handleStartParams(getIntent());

ENABLE_LOADING_INDICATION = !RhoConf.getBool("disable_loading_indication");
//ENABLE_LOADING_INDICATION = !RhoConf.getBool("disable_loading_indication");
}

private void handleStartParams(Intent intent)
@@ -514,25 +473,7 @@ public void onClick(DialogInterface arg0, int arg1) {
*/
return;
}
if (!isPassMotoLicence()) {
AlertDialog.Builder b = new AlertDialog.Builder(this);
b.setCancelable(true);
b.setOnCancelListener( new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) {
RhodesService.exit();
}
});
AlertDialog securityAlert = b.create();
securityAlert.setMessage("Your Motorola licence key is invalid !");
securityAlert.setButton("OK", new DialogInterface.OnClickListener(){
public void onClick(DialogInterface arg0, int arg1) {
RhodesService.exit();
}

});
securityAlert.show();
return;
}


// String urlStart = uri.getPath();
// if (urlStart != null) {
@@ -543,7 +484,7 @@ public void onClick(DialogInterface arg0, int arg1) {
// }
// }
}

private boolean isPassMotoLicence() {
if (Capabilities.MOTOROLA_ENABLED) {
return true;

This file was deleted.

@@ -27,12 +27,18 @@
package com.rhomobile.rhodes;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.Vector;

import com.rhomobile.rhodes.extmanager.Config;
import com.rhomobile.rhodes.extmanager.RhoExtManager;
import com.rhomobile.rhodes.extmanager.WebkitExtension;
import com.rhomobile.rhodes.file.RhoFileApi;
import com.rhomobile.rhodes.signature.Signature;
import com.rhomobile.rhodes.util.Utils;
import com.rhomobile.rhodes.util.Utils.AssetsSource;
import com.rhomobile.rhodes.util.Utils.FileSource;
@@ -41,6 +47,7 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Environment;
import android.os.Handler;
import android.os.Process;
import android.util.Log;
@@ -133,11 +140,52 @@ public void run() {
initClassLoader(getClassLoader());

ApplicationInfo appInfo = getAppInfo();
//File sharedDir = getExternalFilesDir(null);
String sharedPath = null;
String rootPath;

rootPath = RhoFileApi.initRootPath(appInfo.dataDir, appInfo.sourceDir);
rootPath = RhoFileApi.initRootPath(appInfo.dataDir, appInfo.sourceDir, sharedPath);
Log.d(TAG, "Root path: " + rootPath);

InputStream configIs = null;
Config config = new Config();
try {
if (Capabilities.MOTOROLA_ENABLED || Capabilities.WEBKIT_BROWSER_ENABLED || Capabilities.MOTOROLA_BROWSER_ENABLED) {
String externalSharedPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + appInfo.packageName;
File configXmlFile = new File(externalSharedPath, "Config.xml");
if (configXmlFile.exists()) {
Log.i(TAG, "Loading Config.xml from " + configXmlFile.getAbsolutePath());
configIs = new FileInputStream(configXmlFile);
config.load(configIs, configXmlFile.getParent());
} else {
Log.i(TAG, "Loading Config.xml from resources");
configIs = getResources().openRawResource(RhoExtManager.getResourceId("raw", "config"));
config.load(configIs, rootPath);
}
if (Capabilities.SHARED_RUNTIME_ENABLED) {
String startPage = config.getSetting("startpage");
Log.i(TAG,"Start page: " + startPage);
if (startPage != null) {
URI startUri = new URI(startPage);
sharedPath = new File(startUri.getPath()).getParent();
rootPath = RhoFileApi.initRootPath(appInfo.dataDir, appInfo.sourceDir, sharedPath);
}
}
}
} catch (Throwable e) {
//e.printStackTrace();
//Log.e(TAG, e.getMessage());
Log.e(TAG, "Erorr loading RhoElements configuraiton");
} finally {
if (configIs != null) {
try {
configIs.close();
} catch (IOException e) {
// just nothing to do
}
}
}

boolean hashChanged = isAppHashChanged(rootPath);
if (hashChanged) {
Log.i(TAG, "Application hash was changed");
@@ -164,23 +212,29 @@ public void run() {
File testLib = new File(libDir.getPath(), "rhoframework.iseq");
if(libDir.isDirectory() && testLib.isFile())
{
Log.i(TAG, "Updating from very old rhodes version, clean filesystem.");
Logger.I(TAG, "Updating from very old rhodes version, clean filesystem.");
Utils.deleteChildrenIgnoreFirstLevel(new File(rootPath, "apps"), "rhoconfig.txt");
Utils.deleteRecursively(libDir);
}

rootPath = RhoFileApi.initRootPath(appInfo.dataDir, appInfo.sourceDir);
Log.d(TAG, "Root path: " + rootPath);

rootPath = RhoFileApi.initRootPath(appInfo.dataDir, appInfo.sourceDir, sharedPath);
} catch (IOException e) {
Log.e(TAG, e.getMessage());
Logger.E(TAG, e.getMessage());
stop();
return;
}
}

Logger.T(TAG, "Root path: " + rootPath);

RhoFileApi.setFsModeTransparrent(true);

if(Capabilities.WEBKIT_BROWSER_ENABLED || Capabilities.MOTOROLA_BROWSER_ENABLED) {
WebkitExtension.registerWebkitExtension(config);
}
Signature.registerSignatureCaptureExtension();
RhoExtManager.getImplementationInstance().createRhoListeners();

Logger.I(TAG, "Initialized");
}
private static boolean sRhodesActivityStarted = false;
@@ -812,7 +812,7 @@ else if (name.equalsIgnoreCase("phone_id")) {
}
else if (name.equalsIgnoreCase("webview_framework")) {
//return "WEBKIT/" + Build.VERSION.RELEASE;
return "WEBKIT/" + RhodesActivity.safeGetInstance().getMainView().getWebView(-1).getView().getClass().getSimpleName();
return RhodesActivity.safeGetInstance().getMainView().getWebView(-1).getEngineId();
}
}
catch (Exception e) {
@@ -1,5 +1,7 @@
package com.rhomobile.rhodes.extmanager;

import android.graphics.Rect;

public abstract class AbstractRhoExtension implements IRhoExtension {

@Override
@@ -60,7 +62,7 @@ public void onConsole(IRhoExtManager extManager, String message, IRhoExtData ext
}

@Override
public void onInputMethod(IRhoExtManager extManager, boolean enabled, IRhoExtData ext) {
public void onInputMethod(IRhoExtManager extManager, boolean enabled, String type, Rect rect, IRhoExtData ext) {
}

@Override
@@ -76,11 +78,14 @@ public void onAppActivate(IRhoExtManager extManager, boolean bActivate) {

@Override
public void startLocationUpdates(IRhoExtManager extManager, boolean highAccuracy, IRhoExtData ext) {

}

@Override
public void stopLocationUpdates(IRhoExtManager extManager, IRhoExtData ext) {

}

@Override
public void onAuthRequired(IRhoExtManager extManager, String type, String url, String realm, IRhoExtData ext) {
}

}
@@ -0,0 +1,243 @@
package com.rhomobile.rhodes.extmanager;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import android.util.Xml;

import com.rhomobile.rhodes.Logger;


// TODO - make access to map thread-safe

/**
* @author Geoff Day (XFH386, Initial Creation)
* @author Ben Kennedy (NCVT73, Added resource control to load())
*/
public class Config
{
private static final String TAG = Config.class.getSimpleName();

public static final String SETTING_AUTOROTATE = "autorotate";
public static final String SETTING_BADLINK_FILE = "badlinkuri";
public static final String SETTING_DEBUG_BUTTONS_ENABLED = "debugbuttonsenabled";
public static final String SETTING_FULLSCREEN = "fullscreen";
public static final String SETTING_LOG_ERROR = "logerror";
public static final String SETTING_LOG_WARNING = "logwarning";
public static final String SETTING_LOG_INFO = "loginfo";
public static final String SETTING_LOG_USER = "loguser";
public static final String SETTING_LOG_DEBUG = "logdebug";
public static final String SETTING_LOG_URI = "loguri";
public static final String SETTING_LOG_PORT = "logport";
public static final String SETTING_LOG_PROTOCOL = "logprotocol";
public static final String SETTING_LOG_SIZE = "logmaxsize";
public static final String SETTING_NAV_TIMEOUT = "navtimeout";
public static final String SETTING_HTTP_PROXY = "http_proxy";
public static final String SETTING_HTTPS_PROXY = "https_proxy";
public static final String SETTING_PROXY_EXCEPTIONS = "no_proxy";
public static final String SETTING_REGEX_FILE = "regexfile";
public static final String SETTING_SIGNAL_REFRESH = "signalrefresh";
public static final String SETTING_SIP_ENABLE = "enablesip";
public static final String SETTING_START_PAGE = "startpage";
public static final String SETTING_HOURGLASS_LEFT = "hourglassleft";
public static final String SETTING_HOURGLASS_TOP = "hourglasstop";
public static final String SETTING_HOURGLASS_ENABLED = "hourglassenabled";
public static final String SETTING_P1_ENABLED = "enablefunctionkey_f1";
public static final String SETTING_P2_ENABLED = "enablefunctionkey_f2";
public static final String SETTING_P3_ENABLED = "enablefunctionkey_f3";
public static final String METATAG = "metatag";
public static final String GEOLOCATION_ENABLED = "geolocationenabled";

public static final String[] REQUIRED_OPTIONS = { };

public static final String ERROR_TAG_NOT_FOUND = "Required tag: \"%1$s\" not found.";
public static final String ERROR_TAG_EMPTY = "Required tag: \"%1$s\" cannot be empty.";
public static final String ERROR_CONFIG_READ = "Config.xml read error";
public static final String ERROR_BAD_XML = "Bad xml in Config.xml: ";
public static final String ERROR_FILE_NOT_FOUND = "Config.xml cannot be found and attempts in creating Config.xml have failed. Make sure the device is not connected to a PC";

private static ArrayList<String> defaultMetaTag = null;

private HashMap<String, String> settings;

/**
* Initialises the config class
*/
public Config() {
settings = new HashMap<String, String>();
}

/**
* Loads the configuration file from the input stream
*/
public void load(InputStream is, String installDir) throws ConfigException
{
BufferedReader reader = null;
try
{
reader = new BufferedReader(new InputStreamReader(is,"UTF-8"));
Xml.parse(reader, new ConfigHandler(installDir));
}
catch (SAXException e)
{
e.printStackTrace();
throw new ConfigException(ERROR_BAD_XML);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
throw new ConfigException(ERROR_FILE_NOT_FOUND);
}
catch (IOException e)
{
e.printStackTrace();
throw new ConfigException(ERROR_CONFIG_READ);
}
finally
{
if(reader != null)
{
try
{
reader.close();
}
catch (IOException e)
{
//Cant do anything
}
}
}

//Check to see if start page and bad link are there.
for(String requiredSetting: REQUIRED_OPTIONS)
{
if(settings.get(requiredSetting) == null)
{
throw new ConfigException(String.format(ERROR_TAG_NOT_FOUND, requiredSetting));
}
else if(settings.get(requiredSetting).equals(""))
{
throw new ConfigException(String.format(ERROR_TAG_EMPTY, requiredSetting));
}
}
}
/**
* Get string setting value from the name
* @param name in lowercase
* @return setting string value
*/
public String getSetting(String name) {
if (name == null) {
return null;
}
String value = settings.get(name.toLowerCase());
if (value == null) {
int slashindex = name.lastIndexOf("\\");
if (slashindex >= 0) {
String fixedname = name.substring(slashindex+1);
value = settings.get(fixedname.toLowerCase());
}
}
Logger.T(TAG, "getSettings: " + name + "=>" + value);
return value;
}

/**
* Get string setting value from the name
* @param name in lowercase
* @return setting boolean value
*/
boolean getBooleanSetting(String name) {
try {
return getSetting(name).equals("1");
}
catch(Exception e){return false;}
}

private class ConfigHandler implements ContentHandler
{
private String mInstallDir = "";

public ConfigHandler(String installDir) {
mInstallDir = installDir;
}

@Override
public void characters(char[] ch, int start, int length) throws SAXException {}

@Override
public void endDocument() throws SAXException {}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {}

@Override
public void endPrefixMapping(String prefix) throws SAXException {}

@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {}

@Override
public void processingInstruction(String target, String data) throws SAXException {}

@Override
public void setDocumentLocator(Locator locator) {}

@Override
public void skippedEntity(String name) throws SAXException {}

@Override
public void startDocument() throws SAXException {}

@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
// For now add each setting to the map
String setting = null;
int length = atts.getLength();
for (int i = 0; i < length; i++) {
if (atts.getQName(i).equalsIgnoreCase("value")) {
setting = atts.getValue(i);
}
}

if (setting != null) {
if (qName.equalsIgnoreCase(METATAG)) {
if (defaultMetaTag == null) {
defaultMetaTag = new ArrayList<String>();
}
defaultMetaTag.add(setting);
} else {
String value = setting.replace("%INSTALLDIR%", mInstallDir);
String name = qName.toLowerCase();//localName.toLowerCase();
settings.put(name, value);
Logger.T(TAG, "Set RhoElements config value: " + name + "=>" + value);
}
} else {
String name = qName.toLowerCase();//localName.toLowerCase();
settings.put(name, null);
Logger.T(TAG, "Set RhoElements config value: " + name + "=> null");
}
}

@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {}
}

public class ConfigException extends Exception {
private static final long serialVersionUID = 262061320448820494L;

public ConfigException(String detailMessage) {
super(detailMessage);
}

}
}
@@ -1,12 +1,16 @@
package com.rhomobile.rhodes.extmanager;

import java.util.Map;

import android.view.View;

public interface IRhoExtManager {

void registerExtension(String strName, IRhoExtension ext);
IRhoExtension getExtByName(String strName);

void addRhoListener(IRhoListener listener);

/**
* Web view getter. In case of Motorola WebKit is used it returns object which may be directly casted to NeonEkihView
* @return Current web view instance from MainView
@@ -48,7 +52,18 @@ public interface IRhoExtManager {
void zoomPage(float fZoom);
void zoomText(int nZoom);

// RE shared runtime detect
/**
* Handler to notify RhoExtManager about new configuration value
* @param name - configuration parameter name
* @param value - configuration parameter value
* @return true if value is processed by RhoExtManager
*/
boolean onNewConfigValue(String name, String value);

/**
* Handler to notify RhoExtManager that new configuration is going to apply
* @return true if it is allowed for extension to navigate start page itself
*/
boolean onStartNewConfig();

}
@@ -1,5 +1,7 @@
package com.rhomobile.rhodes.extmanager;

import android.graphics.Rect;

public interface IRhoExtension {

void onSetPropertiesData(IRhoExtManager extManager, String propId, String data, int pos, int total, IRhoExtData ext);
@@ -19,14 +21,15 @@ public interface IRhoExtension {
void onStatus(IRhoExtManager extManager, String status, IRhoExtData ext);
void onTitle(IRhoExtManager extManager, String title, IRhoExtData ext);
void onConsole(IRhoExtManager extManager, String message, IRhoExtData ext);
void onInputMethod(IRhoExtManager extManager, boolean enabled, IRhoExtData ext);
void onInputMethod(IRhoExtManager extManager, boolean enabled, String type, Rect area, IRhoExtData ext);
void onNavigateError(IRhoExtManager extManager, String url, IRhoExtData ext);

void onAppActivate(IRhoExtManager extManager, boolean bActivate);

//EkiohLocation getCachedLocation(IRhoExtManager extManager, IRhoExtData ext);
void startLocationUpdates(IRhoExtManager extManager, boolean highAccuracy, IRhoExtData ext);
void stopLocationUpdates(IRhoExtManager extManager, IRhoExtData ext);
void stopLocationUpdates(IRhoExtManager extManager, IRhoExtData ext);
void onAuthRequired(IRhoExtManager extManager, String type, String url, String realm, IRhoExtData ext);

}

@@ -24,13 +24,14 @@
* http://rhomobile.com
*------------------------------------------------------------------------*/

package com.rhomobile.rhodes;
package com.rhomobile.rhodes.extmanager;

import com.rhomobile.rhodes.RhodesActivity;

import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;

public interface RhodesActivityListener {
public interface IRhoListener {

void onCreate(RhodesActivity activity, Intent intent);
void onStart(RhodesActivity activity);
@@ -41,5 +42,5 @@ public interface RhodesActivityListener {
void onNewIntent(RhodesActivity activity, Intent intent);
Dialog onCreateDialog(RhodesActivity activity, int id/*, Bundle args*/);

void onRhodesActivityStartup(RhodesActivity activity);
void onCreateApplication(IRhoExtManager extManager);
}
@@ -2,8 +2,12 @@

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Hashtable;

import android.app.Dialog;
import android.content.Intent;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -16,11 +20,13 @@
import com.rhomobile.rhodes.WebView;
import com.rhomobile.rhodes.mainview.MainView;
import com.rhomobile.rhodes.util.PerformOnUiThread;
import com.rhomobile.rhodes.util.Utils;

public class RhoExtManagerImpl implements IRhoExtManager {
private static final String TAG = RhoExtManagerImpl.class.getSimpleName();

private Hashtable<String, IRhoExtension> mExtensions;
private Hashtable<String, IRhoExtension> mExtensions = new Hashtable<String, IRhoExtension>();
private ArrayList<IRhoListener> mListeners = new ArrayList<IRhoListener>();
private Object mLicense;
private boolean mFirstNavigate = true;

@@ -30,14 +36,6 @@ private IRhoExtData makeDefExtData(View view) {

private static native void nativeRequireRubyFile(String path);

// private static Class<?> getSubclass(Class<?> clazz, String subclassName) throws ClassNotFoundException {
// Class<?> subClasses [] = clazz.getDeclaredClasses();
// for(Class<?> subClass: subClasses) {
// if(subClass.getSimpleName)
// }
// throw new ClassNotFoundException(subclassName);
// }

static int getResId(String className, String idName) {
className = R.class.getCanonicalName() + "$" + className;
try {
@@ -49,10 +47,6 @@ static int getResId(String className, String idName) {
}
}

public RhoExtManagerImpl() {
mExtensions = new Hashtable<String, IRhoExtension>();
}

@Override
public IRhoExtension getExtByName(String strName) {
synchronized (mExtensions) {
@@ -71,6 +65,13 @@ public void registerExtension(String strName, IRhoExtension ext) {
}
}

@Override
public void addRhoListener(IRhoListener listener) {
if (!mListeners.contains(listener)) {
mListeners.add(listener);
}
}

@Override
public View getWebView() {
MainView mainView = RhodesActivity.safeGetInstance().getMainView();
@@ -181,7 +182,23 @@ public String getBuildConfigItem(String name) {
return RhodesService.getBuildConfig(name);
}

/**
* @return is extension allowed to navigate to its start page
*/
@Override
public boolean onStartNewConfig() {
return Capabilities.SHARED_RUNTIME_ENABLED;
}

/**
* @param name - parameter name
* @param value - parameter value
* @return is parameter accepted by rhodes platform
*/
@Override
public boolean onNewConfigValue(String name, String value) {
return false;
}
//-----------------------------------------------------------------------------------------------------------------
// Rhodes implementation related methods are below

@@ -265,10 +282,10 @@ public void onConsole(View view, String msg) {
}
}

public void onInputMethod(View view, boolean enabled) {
public void onInputMethod(View view, boolean enabled, String type, Rect area) {
synchronized (mExtensions) {
for (IRhoExtension ext : mExtensions.values()) {
ext.onInputMethod(this, enabled, makeDefExtData(view));
ext.onInputMethod(this, enabled, type, area, makeDefExtData(view));
}
}
}
@@ -336,6 +353,14 @@ public void onTitle(View view, String title) {
}
}
}

public void onAuthRequired(View view, String type, String url, String realm) {
synchronized (mExtensions) {
for (IRhoExtension ext : mExtensions.values()) {
ext.onAuthRequired(this, type, url, realm, makeDefExtData(view));
}
}
}

public void startLocationUpdates(View view, boolean val) {
synchronized (mExtensions) {
@@ -352,10 +377,79 @@ public void stopLocationUpdates(View view) {
}
}
}

// RE shared runtime detect
public boolean onStartNewConfig() {
return Capabilities.SHARED_RUNTIME_ENABLED;

public void createRhoListeners() {
for (String classname: RhodesStartupListeners.ourRunnableList) {
if (classname.length() == 0) continue;

Class<? extends IRhoListener> klass = null;
try {
klass = Class.forName(classname).asSubclass(IRhoListener.class);
} catch (ClassNotFoundException e) {
Utils.platformLog("RhodesActivity", "processStartupListeners() : ClassNotFoundException for ["+classname+"]");
e.printStackTrace();
}
IRhoListener listener = null;
try {
if (klass != null) {
listener = klass.newInstance();
}
} catch (InstantiationException e) {
Utils.platformLog("RhodesActivity", "processStartupListeners() : InstantiationException for ["+classname+"]");
e.printStackTrace();
} catch (IllegalAccessException e) {
Utils.platformLog("RhodesActivity", "processStartupListeners() : IllegalAccessException for ["+classname+"]");
e.printStackTrace();
}
if (listener != null) {
listener.onCreateApplication(this);
}
}
}

public void onCreateActivity(RhodesActivity activity, Intent intent) {
for (IRhoListener listener: mListeners) {
listener.onCreate(activity, intent);
}
}
public void onStartActivity(RhodesActivity activity) {
for (IRhoListener listener: mListeners) {
listener.onStart(activity);
}
}
public void onResumeActivity(RhodesActivity activity) {
for (IRhoListener listener: mListeners) {
listener.onResume(activity);
}
}
public void onPauseActivity(RhodesActivity activity) {
for (IRhoListener listener: mListeners) {
listener.onPause(activity);
}
}
public void onStopActivity(RhodesActivity activity) {
for (IRhoListener listener: mListeners) {
listener.onStop(activity);
}
}
public void onDestroyActivity(RhodesActivity activity) {
for (IRhoListener listener: mListeners) {
listener.onDestroy(activity);
}
}
public void onNewIntent(RhodesActivity activity, Intent intent) {
for (IRhoListener listener: mListeners) {
listener.onNewIntent(activity, intent);
}
}
public Dialog onCreateDialog(RhodesActivity activity, int id/*, Bundle args*/) {
Dialog res = null;
for (IRhoListener listener: mListeners) {
res = listener.onCreateDialog(activity, id);
if (res != null)
break;
}
return res;
}

}
@@ -0,0 +1,9 @@
// WARNING! THIS FILE IS GENERATED AUTOMATICALLY! DO NOT EDIT IT MANUALLY!
package com.rhomobile.rhodes.extmanager;

class RhodesStartupListeners {

public static final String[] ourRunnableList = { ""
};

}
@@ -0,0 +1,53 @@
package com.rhomobile.rhodes.extmanager;

import android.content.Context;
import android.graphics.Rect;
import android.view.inputmethod.InputMethodManager;

import com.rhomobile.rhodes.Logger;
import com.rhomobile.rhodes.util.ContextFactory;

public class WebkitExtension extends AbstractRhoExtension implements IRhoExtension {
public static final String EXTNAME = "MotorolaWebkit";
private static final String TAG = WebkitExtension.class.getSimpleName();

private static WebkitExtension mInstance;

private Config mConfig;

public static WebkitExtension getInstance() {
return mInstance;
}

private WebkitExtension(Config config) {
mConfig = config;
}

public Config getConfig() {
return mConfig;
}

@Override
public void onInputMethod(IRhoExtManager extManager, boolean enabled, String type, Rect rect, IRhoExtData ext) {
InputMethodManager imm = (InputMethodManager) ContextFactory.getUiContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (enabled) {
imm.showSoftInput(ext.getWebView(), 0);
} else {
imm.hideSoftInputFromWindow(ext.getWebView().getApplicationWindowToken(), 0);
}
}

@Override
public void startLocationUpdates(IRhoExtManager extManager, boolean highAccuracy, IRhoExtData ext) {
}

@Override
public void stopLocationUpdates(IRhoExtManager extManager, IRhoExtData ext) {
}

public static void registerWebkitExtension(Config config) {
mInstance = new WebkitExtension(config);
RhoExtManager.getInstance().registerExtension(EXTNAME, mInstance);
}

}
@@ -60,7 +60,7 @@ public class RhoFileApi {
private static final String DB_FILES_FOLDER = "db/db-files";
private static final String TMP_FOLDER = "tmp";

private static native void nativeInitPath(String rootPath, String sqliteJournalsPath, String apkPath);
private static native void nativeInitPath(String rootPath, String sqliteJournalsPath, String apkPath, String sharedPath);
private static native void nativeInit();
private static native void updateStatTable(String path, String type, long size, long mtime);

@@ -130,12 +130,10 @@ private static void copyAssets(String assets[])
}
}

public static String initRootPath(String dataDir, String sourceDir) {
public static String initRootPath(String dataDir, String sourceDir, String sharedDir) {

root = dataDir + "/rhodata/";
String sqliteJournals = dataDir + "/sqlite_stmt_journals/";
Log.d(TAG, "App root path: " + root);
Log.d(TAG, "Sqlite journals path: " + sqliteJournals);

File f = new File(getRootPath());
f.mkdirs();
@@ -148,7 +146,15 @@ public static String initRootPath(String dataDir, String sourceDir) {

String apkPath = sourceDir;

nativeInitPath(root, sqliteJournals, apkPath);
if (sharedDir == null || sharedDir.length() == 0) {
sharedDir = root;
}

Log.d(TAG, "App root path: " + root);
Log.d(TAG, "Sqlite journals path: " + sqliteJournals);
Log.d(TAG, "Shared path: " + sharedDir);

nativeInitPath(root, sqliteJournals, apkPath, sharedDir);
return root;
}

@@ -276,7 +282,7 @@ public static InputStream openInPackage(String path)
return is;
}
catch (IOException e) {
//Log.e(TAG, "Can not open " + path);
Log.e(TAG, e.getMessage());
return null;
}
}
@@ -219,6 +219,10 @@ private void checkProviderDisabled(RhoLocationListener listener) {
}

private synchronized void setLocation(Location location) {
if (location == null) {
Logger.T(TAG, "setCurrentGpsLocation: location = null");
return;
}
Logger.T(TAG, "setCurrentGpsLocation: location=" + location);
try {
// We've received location update
@@ -26,27 +26,22 @@

package com.rhomobile.rhodes.mainview;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.Vector;

import com.rhomobile.rhodes.AndroidR;
import com.rhomobile.rhodes.Capabilities;
import com.rhomobile.rhodes.Logger;
import com.rhomobile.rhodes.RhodesActivity;
import com.rhomobile.rhodes.RhodesAppOptions;
import com.rhomobile.rhodes.RhodesApplication;
import com.rhomobile.rhodes.RhodesService;
import com.rhomobile.rhodes.file.RhoFileApi;
import com.rhomobile.rhodes.mainview.MainView;
import com.rhomobile.rhodes.nativeview.IRhoCustomView;
import com.rhomobile.rhodes.nativeview.RhoNativeViewManager;
import com.rhomobile.rhodes.util.ContextFactory;
import com.rhomobile.rhodes.util.PerformOnUiThread;
import com.rhomobile.rhodes.util.Utils;
import com.rhomobile.rhodes.webview.IRhoWebView;
import com.rhomobile.rhodes.webview.GoogleWebView;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -58,7 +53,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.AbsoluteLayout;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
@@ -69,27 +63,20 @@ public class SimpleMainView implements MainView {
private final static String TAG = "SimpleMainView";

private static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
private static final int FILL_PARENT = ViewGroup.LayoutParams.FILL_PARENT;
private static final int FILL_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;

private class ActionBack implements View.OnClickListener {
public void onClick(View v) {
goBack();//back(0);
}
};

private void addWebViewToMainView(View webView, int index, LinearLayout.LayoutParams params) {
Context ctx = RhodesActivity.getContext();
AbsoluteLayout containerView = new AbsoluteLayout(ctx);

containerView.addView(webView, new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT, AbsoluteLayout.LayoutParams.MATCH_PARENT, 0, 0));

view.addView(containerView, index, params);
private void addWebViewToMainView(IRhoWebView webView, int index, LinearLayout.LayoutParams params) {
view.addView(webView.getContainerView(), index, params);
}

private void removeWebViewFromMainView() {
ViewGroup pv = (ViewGroup)webView.getView().getParent();
pv.removeView(webView.getView());
view.removeView(pv);
view.removeView(webView.getContainerView());
}

public class MyView extends LinearLayout {
@@ -162,8 +149,7 @@ public void run() {

private LinearLayout view;
private IRhoWebView webView;
private RhoNativeViewManager.RhoNativeView mNativeView = null;
private View mNativeViewView = null;
private IRhoCustomView mRhoCustomView = null;
private LinearLayout navBar = null;
private LinearLayout toolBar = null;

@@ -179,52 +165,40 @@ public IRhoWebView getWebView(int tab_index) {
return webView;
}

public void setNativeView(RhoNativeViewManager.RhoNativeView nview) {
restoreWebView();
mNativeView = nview;
mNativeViewView = mNativeView.getView();
if (mNativeViewView != null) {
//view.removeView(webView.getView());
removeWebViewFromMainView();
//int view_index = 0;
//if (navBar != null) {
//view_index = 1;
//}
if (navBar != null) {
view.removeView(navBar);
}
if (toolBar != null) {
view.removeView(toolBar);
}
int index = 0;
if (navBar != null) {
view.addView(navBar, index);
index++;
}
view.addView( mNativeViewView, index, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));
index++;
if (toolBar != null) {
view.addView(toolBar, index);
}

//view.bringChildToFront(mNativeViewView);
//view.requestLayout();
}
else {
mNativeView = null;
mNativeViewView = null;
}
}

public void restoreWebView() {
if (mNativeView != null) {
view.removeView(mNativeViewView);
mNativeViewView = null;
//int view_index = 0;
//if (navBar != null) {
//view_index = 1;
//}

public void setCustomView(IRhoCustomView customView) {
restoreWebView();
if (customView != null) {
removeWebViewFromMainView();

mRhoCustomView = customView;

if (navBar != null) {
view.removeView(navBar);
}
if (toolBar != null) {
view.removeView(toolBar);
}
int index = 0;
if (navBar != null) {
view.addView(navBar, index);
index++;
}
view.addView(customView.getContainerView(), index, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));
index++;
if (toolBar != null) {
view.addView(toolBar, index);
}
} else {
mRhoCustomView = null;
}
}

public void restoreWebView() {
if (mRhoCustomView != null) {
view.removeView(mRhoCustomView.getContainerView());
mRhoCustomView.destroyView();
mRhoCustomView = null;

if (navBar != null) {
view.removeView(navBar);
}
@@ -237,28 +211,23 @@ public void restoreWebView() {
view.addView(navBar, index);
index++;
}
//view.addView(webView.getView(), index, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));
addWebViewToMainView(webView.getView(), index, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));

addWebViewToMainView(webView, index, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));
index++;
if (toolBar != null) {
view.addView(toolBar, index);
}

//view.bringChildToFront(webView);

mNativeView.destroyView();
mNativeView = null;
//view.requestLayout();
}
}


if (mRhoCustomView != null) {
mRhoCustomView.destroyView();
mRhoCustomView = null;
}
}

private String processForNativeView(String _url) {
StringBuilder s = new StringBuilder("processForNativeView : [");
s.append(_url);
s.append("]");
Utils.platformLog(TAG, s.toString());

Logger.T(TAG, "processForNativiewView: " + _url);

String url = _url;
String callback_prefix = "call_stay_native";

@@ -276,20 +245,18 @@ private String processForNativeView(String _url) {
return cleared_url;
}
// check protocol for nativeView
RhoNativeViewManager.RhoNativeView nvf = RhoNativeViewManager.getNativeViewByteType(protocol);
IRhoCustomView nvf = RhoNativeViewManager.getNativeViewByType(protocol);
if (nvf != null) {
// we should switch to NativeView
//restoreWebView();
if (mNativeView != null) {
if ( !protocol.equals(mNativeView.getViewType()) ) {
setNativeView(nvf);
if (mRhoCustomView != null) {
if ( !protocol.equals(mRhoCustomView.getViewType()) ) {
setCustomView(nvf);
}
}
else {
setNativeView(nvf);
setCustomView(nvf);
}
if (mNativeView != null) {
mNativeView.navigate(navto);
if (mRhoCustomView != null) {
mRhoCustomView.navigate(navto);
return "";
}
}
@@ -322,7 +289,6 @@ public IRhoWebView detachWebView() {
restoreWebView();
IRhoWebView v = null;
if (webView != null) {
//view.removeView(webView.getView());
removeWebViewFromMainView();
v = webView;
webView = null;
@@ -445,7 +411,7 @@ else if (action.equalsIgnoreCase("separator"))
private void setupToolbar(LinearLayout tool_bar, Object params) {
Context ctx = RhodesActivity.getContext();

mCustomBackgroundColorEnable = false;
mCustomBackgroundColorEnable = false;

Vector<Object> buttons = null;
if (params != null) {
@@ -547,7 +513,7 @@ private void init(IRhoWebView v, Object params) {
if (webView == null) {
webView = activity.createWebView();
}
addWebViewToMainView(webView.getView(), 0, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));
addWebViewToMainView(webView, 0, new LinearLayout.LayoutParams(FILL_PARENT, 0, 1));

LinearLayout bottom = new LinearLayout(activity);
bottom.setOrientation(LinearLayout.HORIZONTAL);
@@ -574,11 +540,12 @@ public SimpleMainView(IRhoWebView v, Object params) {

public void setWebBackgroundColor(int color) {
view.setBackgroundColor(color);
webView.getContainerView().setBackgroundColor(color);
webView.getView().setBackgroundColor(color);
}
public void back(int index) {
restoreWebView();

public void back(int index) {
restoreWebView();

boolean bStartPage = RhodesService.isOnStartPage();

@@ -587,12 +554,10 @@ public void back(int index) {
}
else
{
RhodesActivity ra = RhodesActivity.getInstance();
if ( ra != null )
ra.moveTaskToBack(true);
RhodesActivity.safeGetInstance().moveTaskToBack(true);
}
}
}

public void goBack()
{
RhodesService.navigateBack();
@@ -618,34 +583,37 @@ public void navigate(String url, int index) {
public void executeJS(String js, int index) {
com.rhomobile.rhodes.WebView.executeJs(js, index);
}

public void reload(int index) {
if (mNativeViewView != null) {
mNativeViewView.invalidate();
if (mRhoCustomView != null) {
mRhoCustomView.getView().invalidate();
}
else {
webView.reload();
}
}

public void stopNavigate(int index) {
if (mNativeViewView == null) {
if (mRhoCustomView == null) {
webView.stopLoad();
}
else {
mRhoCustomView.stop();
}
}

public String currentLocation(int index) {
return webView.getUrl();
}

public void switchTab(int index) {
// Nothing
}

public int activeTab() {
return 0;
}

public void loadData(String data, int index) {
restoreWebView();
webView.loadData(data, "text/html", "utf-8");
@@ -76,7 +76,7 @@ public SplashScreen(Context context, IRhoWebView webView, SplashScreenListener l
mView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
AssetManager am = context.getResources().getAssets();
mWebView = loadContent(am, webView);
mView.addView(mWebView.getView());
mView.addView(mWebView.getContainerView());
}

public synchronized String getUrlToNavigate() { return mUrlToNavigate; }
@@ -193,7 +193,7 @@ public void run() {
public IRhoWebView detachWebView() {
IRhoWebView v = null;
if (mWebView != null) {
mView.removeView(mWebView.getView());
mView.removeView(mWebView.getContainerView());
v = mWebView;
mWebView = null;
}
@@ -610,15 +610,16 @@ else if (params instanceof Map<?,?>) {

SimpleMainView view = null;
if (use_current_view_for_tab) {
RhodesService r = RhodesService.getInstance();
MainView mainView = r.getMainView();
MainView mainView = RhodesActivity.safeGetInstance().getMainView();
action = mainView.currentLocation(-1);
IRhoWebView webView = mainView.detachWebView();
view = new SimpleMainView(webView);
}
if (view == null) {
view = new SimpleMainView();
view.getWebView(-1).setWebClient(RhodesActivity.safeGetInstance());
}

// Set view factory

if (web_bkg_color_Obj != null) {
@@ -238,6 +238,10 @@ public Bitmap getResultBitmap() {
return mResultBitmap;
}

public int getResultBitmapID() {
return MapBitmapManager.getSharedInstance().addBitmap(mResultBitmap);
}

// return modifier for Y coordinates from ancor point.
public int getXOffset() {
return mXOffset;
@@ -0,0 +1,124 @@
/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

package com.rhomobile.rhodes.mapview;


import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Hashtable;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.graphics.Bitmap;

import com.rhomobile.rhodes.Logger;
import com.rhomobile.rhodes.util.Utils;

public class MapBitmapManager {

private static final String TAG = MapBitmapManager.class.getSimpleName();


private static int ourBitmapGlobalID = 0;

private class BitmapHolder {
public Bitmap bitmap;
public int refCount;
}



private Hashtable<Integer, BitmapHolder> mBitmaps = null;

private static MapBitmapManager ourManager = null;

public MapBitmapManager() {
mBitmaps = new Hashtable<Integer, BitmapHolder>();
}

public static MapBitmapManager getSharedInstance() {
if (ourManager == null) {
ourManager = new MapBitmapManager();
}
return ourManager;
}

public Bitmap getBitmap(int id) {
BitmapHolder bh = mBitmaps.get(new Integer(id));
if (bh == null) {
return null;
}
return bh.bitmap;
}

public int addBitmap(Bitmap bitmap) {
int id = 0;
synchronized (mBitmaps) {
BitmapHolder bh = new BitmapHolder();
bh.bitmap = bitmap;
bh.refCount = 1;
id = ++ourBitmapGlobalID;
mBitmaps.put(new Integer(id), bh);
}
//Logger.I(TAG, "addBitmap() return "+String.valueOf(id));
return id;
}

public void releaseBitmap(int id) {
//Logger.I(TAG, "releaseBitmap("+String.valueOf(id)+")");
synchronized (mBitmaps) {
BitmapHolder bh = mBitmaps.get(new Integer(id));
if (bh != null) {
bh.refCount--;
if (bh.refCount <= 0) {
//Logger.I(TAG, "releaseBitmap() REAL REMOVE");
bh.bitmap.recycle();
mBitmaps.remove(new Integer(id));
}
}
}
}

public void addRef(int id) {
BitmapHolder bh = mBitmaps.get(new Integer(id));
if (bh != null) {
bh.refCount++;
}
}

public void totalClean() {
synchronized (mBitmaps) {
mBitmaps.clear();
}
}


}