ruboto-core 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/Gemfile.lock +16 -0
- data/README.md +65 -3
- data/Rakefile +1 -135
- data/assets/Rakefile +2 -0
- data/assets/assets/scripts/ruboto.rb +243 -97
- data/assets/src/InheritingClass.java +28 -0
- data/assets/src/RubotoActivity.java +122 -0
- data/assets/src/RubotoBroadcastReceiver.java +77 -0
- data/assets/src/RubotoService.java +75 -0
- data/bin/ruboto +732 -44
- data/lib/java_class_gen/android_api.xml +1 -0
- metadata +11 -11
- data/assets/src/org/ruboto/RubotoActivity.java +0 -1406
- data/assets/src/org/ruboto/RubotoBroadcastReceiver.java +0 -126
- data/assets/src/org/ruboto/RubotoService.java +0 -233
- data/assets/src/org/ruboto/RubotoView.java +0 -30
- data/lib/java_class_gen/RubotoClass.java.erb +0 -197
- data/lib/java_class_gen/callback_reflection.rb +0 -109
- data/lib/java_class_gen/interfaces.txt +0 -1
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
data/README.md
CHANGED
@@ -31,6 +31,7 @@ Command-line Tools
|
|
31
31
|
|
32
32
|
* [Application generator](#application_generator) (like the rails application generator)
|
33
33
|
* [Class generator](#class_generator) to generate additional Activities, BroadcastReceivers, Services, etc.
|
34
|
+
* [Callback generator](#class_generator) to generate specific subclasses to open up access (callbacks) for various portions of the Android API.
|
34
35
|
* [Packaging task](#packaging_task) to generate an apk file
|
35
36
|
* [Deployment task](#deployment_task) to deploy a generated package to an emulator or connected device
|
36
37
|
* [Develop without having to compile to try every change](#update_scripts)
|
@@ -39,16 +40,52 @@ Command-line Tools
|
|
39
40
|
<a name="application_generator"></a>
|
40
41
|
### Application generator
|
41
42
|
|
42
|
-
$ ruboto gen app --package com.yourdomain.whatever --path path/to/where/you/want/the/app --name NameOfApp --target android-version --activity MainActivityName
|
43
|
-
|
43
|
+
$ ruboto gen app --package com.yourdomain.whatever --path path/to/where/you/want/the/app --name NameOfApp --target android-version --min_sdk another-android-version --activity MainActivityName
|
44
|
+
Version values must be specified using'android-' and the sdk level number (e.g., android-8 is froyo).
|
44
45
|
|
45
46
|
<a name="class_generator"></a>
|
46
47
|
### Class generator
|
47
48
|
|
49
|
+
Generates a Java class (Activity, Service, or BroadcastReceiver) associated with a specific ruboto script.
|
50
|
+
|
48
51
|
$ ruboto gen class ClassName --name YourObjectName
|
49
52
|
Ex:
|
50
53
|
$ ruboto gen class BroadcastReceiver --name AwesomenessReceiver
|
51
54
|
|
55
|
+
<a name="callback_generator"></a>
|
56
|
+
### Callback generator
|
57
|
+
|
58
|
+
Can subclass any part of the Android API to pass control over to a script when the specified methods are called. You can also create classes that implement a single Android interface to pass control over to ruboto.
|
59
|
+
|
60
|
+
For classes that need subclassing (e.g., PhoneStateListener, SQLiteOpenHelper, View)
|
61
|
+
|
62
|
+
$ ruboto gen subclass AndroidPackageAndClassName --name YourClassName --method_base all-on-or-none --method_include methods --method_exclude methods
|
63
|
+
Ex:
|
64
|
+
$ ruboto gen class android.telephony.PhoneStateListener --name MyPhoneStateListener
|
65
|
+
|
66
|
+
For interfaces that need implementing (e.g., OnClickListener or SensorListener)
|
67
|
+
|
68
|
+
$ ruboto gen interface AndroidPackageAndInterfaceName --name YourClassName
|
69
|
+
Ex:
|
70
|
+
$ ruboto gen interface android.hardware.SensorListener --name MySensorListener
|
71
|
+
|
72
|
+
Inside your script use:
|
73
|
+
|
74
|
+
# note that this is different than java_import
|
75
|
+
ruboto_import "your.package.MySensorListener"
|
76
|
+
|
77
|
+
Later:
|
78
|
+
|
79
|
+
# Create the callback object
|
80
|
+
@sensor_listener = MySensorListener.new
|
81
|
+
|
82
|
+
# Specify the block to call
|
83
|
+
@sensor_listener.handle_sensor_changed do |sensor, values|
|
84
|
+
# Do stuff
|
85
|
+
end
|
86
|
+
|
87
|
+
# Register the listener
|
88
|
+
|
52
89
|
<a name="packaging_task"></a>
|
53
90
|
### Packaging task
|
54
91
|
|
@@ -100,8 +137,33 @@ Also, you need root access to your device for this to work, as it needs to write
|
|
100
137
|
|
101
138
|
### Updating Ruboto's Files
|
102
139
|
|
103
|
-
|
140
|
+
You can update various portions of your generated Ruboto app through the ruboto command:
|
141
|
+
|
142
|
+
* JRuby:
|
143
|
+
|
144
|
+
1) If a new version of JRuby is released, you should update your gem (e.g., sudo gem update jruby-jars).
|
145
|
+
|
146
|
+
2) From the root directory of your app:
|
147
|
+
|
148
|
+
$ ruboto update jruby
|
149
|
+
|
150
|
+
* The ruboto.rb script:
|
151
|
+
|
152
|
+
1) From the root directory of your app:
|
153
|
+
|
154
|
+
$ ruboto update ruboto
|
155
|
+
|
156
|
+
* The core classes (e.g., RubotoActivity):
|
157
|
+
|
158
|
+
1) These classes are generated on your machine based on the SDKs (min and target) specified when you 'gen app' (stored in the AndroidManifest.xml)
|
159
|
+
|
160
|
+
2) You many want to regenerate them if a new version of the SDK is released, if you change your targets, or if you want more control over the callbacks you receive.
|
161
|
+
|
162
|
+
3) From the root directory of your app:
|
163
|
+
|
164
|
+
$ ruboto gen core Activity --method_base all-on-or-none --method_include specific-methods-to-include --method_include specific-methods-to-exclude
|
104
165
|
|
166
|
+
4) The generator will load up the SDK information and find the specified methods. The generator will abort around methods that were added or deprecated based on the SDK levels. You can either exclude those methods or add --force to create them anyway (added methods are created without calling super to avoid crashin on legacy hardware).
|
105
167
|
|
106
168
|
Scripts
|
107
169
|
-------
|
data/Rakefile
CHANGED
@@ -5,140 +5,6 @@ task :gem do
|
|
5
5
|
end
|
6
6
|
|
7
7
|
task :release do
|
8
|
-
`gem push ruboto-core-
|
9
|
-
end
|
10
|
-
|
11
|
-
require 'erb'
|
12
|
-
|
13
|
-
def unprefixed_class(class_name)
|
14
|
-
/\.([^\.]+)\z/.match(class_name)[1]
|
15
|
-
end
|
16
|
-
|
17
|
-
# active_support/inflector.rb
|
18
|
-
def underscore(camel_cased_word)
|
19
|
-
camel_cased_word.to_s.gsub(/::/, '/').
|
20
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
21
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
22
|
-
tr("-", "_").
|
23
|
-
downcase
|
24
|
-
end
|
25
|
-
|
26
|
-
def transform_return_type(type)
|
27
|
-
if type.include?(".")
|
28
|
-
return type
|
29
|
-
elsif type == "int"
|
30
|
-
return "Integer"
|
31
|
-
else
|
32
|
-
return type.capitalize
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
task :generate_java_classes do
|
37
|
-
all_callbacks = eval(IO.read("lib/java_class_gen/interfaces.txt"))
|
38
|
-
|
39
|
-
@starting_methods = {"BroadcastReceiver" => "onReceive"}
|
40
|
-
@starting_methods.default = "onCreate"
|
41
|
-
|
42
|
-
all_callbacks.each do |full_class, method_hash|
|
43
|
-
@class = unprefixed_class full_class
|
44
|
-
@callbacks = method_hash
|
45
|
-
@full_class = full_class
|
46
|
-
@first_method = @starting_methods[@class]
|
47
|
-
|
48
|
-
|
49
|
-
##############################################################################################
|
50
|
-
#
|
51
|
-
# This code resolves any issues with the generated callbacks.
|
52
|
-
#
|
53
|
-
# 1) Remove callbacks that are hard coded in RubotoActivity.erb:
|
54
|
-
#
|
55
|
-
|
56
|
-
if @class == "Activity"
|
57
|
-
@callbacks["android.view.View$OnCreateContextMenuListener"].delete("onCreateContextMenu")
|
58
|
-
#
|
59
|
-
# 2) Remove callbacks that are causing a problem
|
60
|
-
#
|
61
|
-
@callbacks["android.app.Activity"].delete("onRetainNonConfigurationChildInstances")
|
62
|
-
#
|
63
|
-
# 3) Override the callback constant for a few key callbacks
|
64
|
-
#
|
65
|
-
@callbacks["android.app.Activity"]["onMenuItemSelected"]["constant"] = "CB_CREATE_OPTIONS_MENU"
|
66
|
-
@callbacks["android.app.Activity"]["onContextItemSelected"]["constant"] = "CB_CREATE_CONTEXT_MENU"
|
67
|
-
#
|
68
|
-
# 4) Create a unique name for callbacks that have duplicate names
|
69
|
-
#
|
70
|
-
@callbacks["android.content.DialogInterface$OnClickListener"]["onClick"]["ruby_method"] = "on_dialog_click"
|
71
|
-
@callbacks["android.content.DialogInterface$OnClickListener"]["onClick"]["constant"] = "CB_DIALOG_CLICK"
|
72
|
-
@callbacks["android.content.DialogInterface$OnKeyListener"]["onKey"]["ruby_method"] = "on_dialog_key"
|
73
|
-
@callbacks["android.content.DialogInterface$OnKeyListener"]["onKey"]["constant"] = "CB_DIALOG_KEY"
|
74
|
-
@callbacks["android.content.DialogInterface$OnMultiChoiceClickListener"]["onClick"]["ruby_method"] = "on_dialog_multi_choice_click"
|
75
|
-
@callbacks["android.content.DialogInterface$OnMultiChoiceClickListener"]["onClick"]["constant"] = "CB_DIALOG_MULTI_CHOICE_CLICK"
|
76
|
-
#
|
77
|
-
# 5) Report any duplicate name callbacks not handled
|
78
|
-
#
|
79
|
-
callbacks = {}
|
80
|
-
@callbacks.each do |interface,i_info|
|
81
|
-
i_info.each do |method,v|
|
82
|
-
if callbacks[method] and not v["ruby_method"]
|
83
|
-
puts "#{method} in #{interface} and #{callbacks[method]}"
|
84
|
-
else
|
85
|
-
callbacks[v["ruby_method"] || method] = interface
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
#
|
90
|
-
# 6) Create a few new special case callbacks
|
91
|
-
#
|
92
|
-
@callbacks["none"] = {
|
93
|
-
"onDraw" => {"args" => ["android.view.View", "android.graphics.Canvas"]},
|
94
|
-
"onSizeChanged" => {"args" => ["android.view.View", "int", "int", "int", "int"]}
|
95
|
-
}
|
96
|
-
end
|
97
|
-
#
|
98
|
-
##############################################################################################
|
99
|
-
#
|
100
|
-
# This code takes the callbacks hash (read out of the interfaces.txt file) and prepares
|
101
|
-
# it for use in the code below.
|
102
|
-
#
|
103
|
-
@implements = []
|
104
|
-
@constants = []
|
105
|
-
@callbacks.each do |interface,i_info|
|
106
|
-
i_info.each do |method,v|
|
107
|
-
v["interface"] = interface.gsub("$", ".")
|
108
|
-
v["interface"] = "Activity" if v["interface"] == "android.app.Activity"
|
109
|
-
v["method"] = method
|
110
|
-
v["return_type"] = (v["return_type"] || "void").gsub("$", ".")
|
111
|
-
v["interface_method"] = v["interface_method"] || v["method"]
|
112
|
-
v["ruby_method"] = v["ruby_method"] || v["method"].gsub(/[A-Z]/) {|i| "_#{i.downcase}"}
|
113
|
-
|
114
|
-
@implements << v["interface"] if v["interface"] != full_class and
|
115
|
-
v["interface"] != @class and
|
116
|
-
v["interface"] != "none" and
|
117
|
-
not @implements.include?(v["interface"])
|
118
|
-
|
119
|
-
unless v["constant"]
|
120
|
-
constant = v["method"].gsub(/[A-Z]/) {|i| "_#{i}"}.upcase
|
121
|
-
constant = constant[3..-1] if constant[0..2] == "ON_"
|
122
|
-
v["constant"] = "CB_#{constant}"
|
123
|
-
end
|
124
|
-
@constants << v["constant"] unless @constants.include?(v["constant"]) || v["method"] == @first_method
|
125
|
-
|
126
|
-
v["args"] = (v["args"] || [])
|
127
|
-
v["args_with_types"], v["args_alone"] = [], []
|
128
|
-
v["args"].each_with_index {|arg_type, i| v["args_with_types"] << "#{arg_type.gsub("$", ".")} arg#{i}"; v["args_alone"] << "arg#{i}"}
|
129
|
-
v["args_with_types"] = v["args_with_types"].join(", ")
|
130
|
-
end
|
131
|
-
end
|
132
|
-
##############################################################################################
|
133
|
-
|
134
|
-
|
135
|
-
File.open("assets/src/Inheriting#{@class}.java", "w") do |file|
|
136
|
-
file.write ERB.new(IO.read("lib/java_class_gen/InheritingClass.java.erb"), 0, "%").result
|
137
|
-
end
|
138
|
-
|
139
|
-
File.open("assets/src/org/ruboto/Ruboto#{@class}.java", "w") do |file|
|
140
|
-
file.write ERB.new(IO.read("lib/java_class_gen/RubotoClass.java.erb"), 0, "%").result
|
141
|
-
end
|
142
|
-
end
|
8
|
+
`gem push #{Dir['ruboto-core-*.gem'][-1]}`
|
143
9
|
end
|
144
10
|
|
data/assets/Rakefile
CHANGED
@@ -29,6 +29,8 @@ file jruby_ruboto_jar => generated_libs do
|
|
29
29
|
ant.zip(:destfile=>jruby_ruboto_jar) do
|
30
30
|
zipfileset(:src=>jruby_jar) do
|
31
31
|
exclude(:name=>'jni/**')
|
32
|
+
# dx chokes on some of the netdb classes, for some reason
|
33
|
+
exclude(:name=>'jnr/netdb/**')
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -2,11 +2,14 @@
|
|
2
2
|
#
|
3
3
|
# ruboto.rb (by Scott Moyer)
|
4
4
|
#
|
5
|
-
# Wrapper for using RubotoActivity
|
5
|
+
# - Wrapper for using RubotoActivity, RubotoService, and
|
6
|
+
# RubotoBroadcastReceiver.
|
7
|
+
# - Provides interface for generating UI elements.
|
8
|
+
# - Imports and configures callback classes.
|
6
9
|
#
|
7
10
|
#######################################################
|
8
11
|
|
9
|
-
$RUBOTO_VERSION =
|
12
|
+
$RUBOTO_VERSION = 6
|
10
13
|
|
11
14
|
def confirm_ruboto_version(required_version, exact=true)
|
12
15
|
raise "requires $RUBOTO_VERSION=#{required_version} or greater, current version #{$RUBOTO_VERSION}" if $RUBOTO_VERSION < required_version and not exact
|
@@ -15,9 +18,9 @@ end
|
|
15
18
|
|
16
19
|
require 'java'
|
17
20
|
|
21
|
+
$package_name = "THE_PACKAGE"
|
18
22
|
|
19
|
-
|
20
|
-
%w(Activity Dialog BroadcastReceiver Service View).map do |klass|
|
23
|
+
%w(Activity Dialog BroadcastReceiver Service).map do |klass|
|
21
24
|
java_import "org.ruboto.Ruboto#{klass}"
|
22
25
|
end
|
23
26
|
|
@@ -42,9 +45,9 @@ java_import "android.R"
|
|
42
45
|
java_import "android.util.Log"
|
43
46
|
|
44
47
|
module Ruboto
|
45
|
-
java_import "
|
48
|
+
java_import "#{$package_name}.R"
|
46
49
|
begin
|
47
|
-
Id = JavaUtilities.get_proxy_class("
|
50
|
+
Id = JavaUtilities.get_proxy_class("#{$package_name}.R$id")
|
48
51
|
rescue NameError
|
49
52
|
Log.d "RUBOTO", "no R$id"
|
50
53
|
end
|
@@ -58,16 +61,14 @@ AndroidIds = JavaUtilities.get_proxy_class("android.R$id")
|
|
58
61
|
#
|
59
62
|
|
60
63
|
class Activity
|
61
|
-
attr_accessor :init_block
|
62
|
-
|
63
64
|
def start_ruboto_dialog(remote_variable, &block)
|
64
65
|
start_ruboto_activity(remote_variable, RubotoDialog, &block)
|
65
66
|
end
|
66
67
|
|
67
68
|
def start_ruboto_activity(remote_variable, klass=RubotoActivity, &block)
|
68
|
-
|
69
|
+
$activity_init_block = block
|
69
70
|
|
70
|
-
if @initialized or not self.
|
71
|
+
if @initialized or not self.kind_of?(RubotoActivity)
|
71
72
|
b = Bundle.new
|
72
73
|
b.putString("Remote Variable", remote_variable)
|
73
74
|
b.putBoolean("Define Remote Variable", true)
|
@@ -101,112 +102,134 @@ end
|
|
101
102
|
|
102
103
|
#############################################################################
|
103
104
|
#
|
104
|
-
#
|
105
|
+
# Configure a class to work with handlers
|
105
106
|
#
|
106
107
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
#
|
119
|
-
# Option Menus
|
120
|
-
#
|
121
|
-
|
122
|
-
def add_menu title, icon=nil, &block
|
123
|
-
mi = @menu.add(title)
|
124
|
-
mi.setIcon(icon) if icon
|
125
|
-
mi.class.class_eval {attr_accessor :on_click}
|
126
|
-
mi.on_click = block
|
127
|
-
end
|
128
|
-
|
129
|
-
def handle_create_options_menu &block
|
130
|
-
requestCallback RubotoActivity::CB_CREATE_OPTIONS_MENU
|
131
|
-
@create_options_menu_block = block
|
132
|
-
end
|
133
|
-
|
134
|
-
def on_create_options_menu(*args)
|
135
|
-
@menu, @context_menu = args[0], nil
|
136
|
-
instance_eval {@create_options_menu_block.call(*args)} if @create_options_menu_block
|
137
|
-
end
|
138
|
-
|
139
|
-
def on_menu_item_selected(num,menu_item)
|
140
|
-
(instance_eval &(menu_item.on_click); return true) if @menu
|
141
|
-
false
|
142
|
-
end
|
108
|
+
def ruboto_allow_handlers(klass)
|
109
|
+
klass.class_eval do
|
110
|
+
def method_missing(name, *args, &block)
|
111
|
+
if name.to_s =~ /^handle_(.*)/ and (const = self.class.const_get("CB_#{$1.upcase}"))
|
112
|
+
setCallbackProc(const, block)
|
113
|
+
self
|
114
|
+
else
|
115
|
+
super
|
116
|
+
end
|
117
|
+
end
|
143
118
|
|
144
|
-
|
145
|
-
|
146
|
-
|
119
|
+
def respond_to?(name)
|
120
|
+
return true if name.to_s =~ /^handle_(.*)/ and self.class.const_get("CB_#{$1.upcase}")
|
121
|
+
super
|
122
|
+
end
|
147
123
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
124
|
+
def initialize_handlers(&block)
|
125
|
+
instance_eval &block
|
126
|
+
self
|
127
|
+
end
|
152
128
|
end
|
129
|
+
klass
|
130
|
+
end
|
153
131
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
132
|
+
#############################################################################
|
133
|
+
#
|
134
|
+
# Activity Subclass Setup
|
135
|
+
#
|
158
136
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
137
|
+
def ruboto_configure_activity(klass)
|
138
|
+
klass.class_eval do
|
139
|
+
#
|
140
|
+
# Initialize
|
141
|
+
#
|
163
142
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
end
|
143
|
+
def initialize_activity()
|
144
|
+
instance_eval &$activity_init_block
|
145
|
+
@initialized = true
|
146
|
+
self
|
147
|
+
end
|
169
148
|
|
170
|
-
|
171
|
-
|
172
|
-
def when_launched(&block)
|
173
|
-
instance_exec *args, &block
|
174
|
-
on_create nil
|
149
|
+
def handle_finish_create &block
|
150
|
+
@finish_create_block = block
|
175
151
|
end
|
176
152
|
|
177
|
-
def
|
178
|
-
@
|
153
|
+
def setup_content &block
|
154
|
+
@content_view_block = block
|
179
155
|
end
|
180
156
|
|
181
157
|
def on_create(bundle)
|
158
|
+
@view_parent = nil
|
182
159
|
setContentView(instance_eval &@content_view_block) if @content_view_block
|
183
|
-
instance_eval {@
|
160
|
+
instance_eval {@finish_create_block.call} if @finish_create_block
|
184
161
|
end
|
185
162
|
|
186
|
-
#
|
187
|
-
|
188
|
-
|
189
|
-
|
163
|
+
#
|
164
|
+
# Option Menus
|
165
|
+
#
|
166
|
+
|
167
|
+
def add_menu title, icon=nil, &block
|
168
|
+
mi = @menu.add(title)
|
169
|
+
mi.setIcon(icon) if icon
|
170
|
+
mi.class.class_eval {attr_accessor :on_click}
|
171
|
+
mi.on_click = block
|
172
|
+
|
173
|
+
# Seems to be needed or the block might get cleaned up
|
174
|
+
@all_menu_items = [] unless @all_menu_items
|
175
|
+
@all_menu_items << mi
|
176
|
+
end
|
177
|
+
|
178
|
+
def handle_create_options_menu &block
|
179
|
+
p = Proc.new do |*args|
|
180
|
+
@menu, @context_menu = args[0], nil
|
181
|
+
instance_eval {block.call(*args)} if block
|
182
|
+
end
|
183
|
+
setCallbackProc(self.class.const_get("CB_CREATE_OPTIONS_MENU"), p)
|
184
|
+
|
185
|
+
p = Proc.new do |num,menu_item|
|
186
|
+
(instance_eval &(menu_item.on_click); return true) if @menu
|
187
|
+
false
|
188
|
+
end
|
189
|
+
setCallbackProc(self.class.const_get("CB_MENU_ITEM_SELECTED"), p)
|
190
190
|
end
|
191
191
|
|
192
192
|
#
|
193
|
-
#
|
193
|
+
# Context Menus
|
194
194
|
#
|
195
195
|
|
196
|
-
def
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
196
|
+
def add_context_menu title, &block
|
197
|
+
mi = @context_menu.add(title)
|
198
|
+
mi.class.class_eval {attr_accessor :on_click}
|
199
|
+
mi.on_click = block
|
200
|
+
|
201
|
+
# Seems to be needed or the block might get cleaned up
|
202
|
+
@all_menu_items = [] unless @all_menu_items
|
203
|
+
@all_menu_items << mi
|
204
|
+
end
|
205
|
+
|
206
|
+
def handle_create_context_menu &block
|
207
|
+
p = Proc.new do |*args|
|
208
|
+
@menu, @context_menu = nil, args[0]
|
209
|
+
instance_eval {block.call(*args)} if block
|
204
210
|
end
|
211
|
+
setCallbackProc(self.class.const_get("CB_CREATE_CONTEXT_MENU"), p)
|
212
|
+
|
213
|
+
p = Proc.new do |menu_item|
|
214
|
+
(instance_eval {menu_item.on_click.call(menu_item.getMenuInfo.position)}; return true) if menu_item.on_click
|
215
|
+
false
|
216
|
+
end
|
217
|
+
setCallbackProc(self.class.const_get("CB_CONTEXT_ITEM_SELECTED"), p)
|
205
218
|
end
|
219
|
+
end
|
206
220
|
|
207
|
-
|
208
|
-
|
209
|
-
|
221
|
+
ruboto_allow_handlers(klass)
|
222
|
+
end
|
223
|
+
ruboto_configure_activity(RubotoActivity)
|
224
|
+
|
225
|
+
RUBOTO_CLASSES.each do |klass|
|
226
|
+
# Setup ability to handle callbacks
|
227
|
+
ruboto_allow_handlers(klass)
|
228
|
+
|
229
|
+
klass.class_eval do
|
230
|
+
def when_launched(&block)
|
231
|
+
instance_exec *args, &block
|
232
|
+
on_create nil
|
210
233
|
end
|
211
234
|
|
212
235
|
eval %Q{
|
@@ -217,7 +240,6 @@ RUBOTO_CLASSES.each do |klass|
|
|
217
240
|
end
|
218
241
|
end
|
219
242
|
|
220
|
-
|
221
243
|
#############################################################################
|
222
244
|
#
|
223
245
|
# RubotoActivity View Generation
|
@@ -227,8 +249,8 @@ def ruboto_import_widgets(*widgets)
|
|
227
249
|
widgets.each{|i| ruboto_import_widget i}
|
228
250
|
end
|
229
251
|
|
230
|
-
def ruboto_import_widget(class_name)
|
231
|
-
view_class = java_import "
|
252
|
+
def ruboto_import_widget(class_name, package_name="android.widget")
|
253
|
+
view_class = java_import "#{package_name}.#{class_name}"
|
232
254
|
return unless view_class
|
233
255
|
|
234
256
|
RubotoActivity.class_eval "
|
@@ -246,14 +268,14 @@ def ruboto_import_widget(class_name)
|
|
246
268
|
"
|
247
269
|
end
|
248
270
|
|
249
|
-
# Need to load these two to extend classes
|
250
|
-
ruboto_import_widgets :ListView, :Button
|
251
|
-
|
252
271
|
#############################################################################
|
253
272
|
#
|
254
273
|
# Extend Common View Classes
|
255
274
|
#
|
256
275
|
|
276
|
+
# Need to load these two to extend classes
|
277
|
+
ruboto_import_widgets :ListView, :Button
|
278
|
+
|
257
279
|
class View
|
258
280
|
@@convert_params = {
|
259
281
|
:wrap_content => ViewGroup::LayoutParams::WRAP_CONTENT,
|
@@ -308,3 +330,127 @@ class Button
|
|
308
330
|
super(context, params)
|
309
331
|
end
|
310
332
|
end
|
333
|
+
|
334
|
+
#############################################################################
|
335
|
+
#
|
336
|
+
# Import a class and set it up for handlers
|
337
|
+
#
|
338
|
+
|
339
|
+
def ruboto_import(package_class)
|
340
|
+
klass = java_import package_class
|
341
|
+
return unless klass
|
342
|
+
ruboto_allow_handlers(klass)
|
343
|
+
end
|
344
|
+
|
345
|
+
#############################################################################
|
346
|
+
#
|
347
|
+
# Allows RubotoActivity to handle callbacks covering Class based handlers
|
348
|
+
#
|
349
|
+
|
350
|
+
def ruboto_register_handler(handler_class, unique_name, for_class, method_name)
|
351
|
+
klass_name = handler_class[/.+\.([A-Z].+)/,1]
|
352
|
+
klass = ruboto_import handler_class
|
353
|
+
return unless klass
|
354
|
+
|
355
|
+
RubotoActivity.class_eval "
|
356
|
+
attr_accessor :#{unique_name}_handler
|
357
|
+
|
358
|
+
def #{unique_name}_handler
|
359
|
+
@#{unique_name}_handler ||= #{klass_name}.new
|
360
|
+
end
|
361
|
+
|
362
|
+
def handle_#{unique_name}(&block)
|
363
|
+
#{unique_name}_handler.handle_#{unique_name} &block
|
364
|
+
self
|
365
|
+
end
|
366
|
+
"
|
367
|
+
|
368
|
+
for_class.class_eval "
|
369
|
+
alias_method :orig_#{method_name}, :#{method_name}
|
370
|
+
def #{method_name}(handler)
|
371
|
+
orig_#{method_name}(handler.kind_of?(RubotoActivity) ? handler.#{unique_name}_handler : handler)
|
372
|
+
end
|
373
|
+
"
|
374
|
+
end
|
375
|
+
|
376
|
+
ruboto_register_handler("org.ruboto.callbacks.RubotoOnClickListener", "click", Button, "setOnClickListener")
|
377
|
+
ruboto_register_handler("org.ruboto.callbacks.RubotoOnItemClickListener", "item_click", ListView, "setOnItemClickListener")
|
378
|
+
|
379
|
+
#############################################################################
|
380
|
+
#
|
381
|
+
# RubotoPreferenceActivity Preference Generation
|
382
|
+
#
|
383
|
+
|
384
|
+
def ruboto_import_preferences(*preferences)
|
385
|
+
preferences.each{|i| ruboto_import_preference i}
|
386
|
+
end
|
387
|
+
|
388
|
+
def ruboto_import_preference(class_name, package_name="android.preference")
|
389
|
+
klass = java_import "#{package_name}.#{class_name}"
|
390
|
+
return unless klass
|
391
|
+
|
392
|
+
setup_preferences
|
393
|
+
|
394
|
+
RubotoPreferenceActivity.class_eval "
|
395
|
+
def #{(class_name.to_s.gsub(/([A-Z])/) {'_' + $1.downcase})[1..-1]}(params={})
|
396
|
+
rv = #{class_name}.new self
|
397
|
+
rv.configure self, params
|
398
|
+
@parent.addPreference(rv) if @parent
|
399
|
+
if block_given?
|
400
|
+
old_parent, @parent = @parent, rv
|
401
|
+
yield
|
402
|
+
@parent = old_parent
|
403
|
+
end
|
404
|
+
rv
|
405
|
+
end
|
406
|
+
"
|
407
|
+
end
|
408
|
+
|
409
|
+
def setup_preferences
|
410
|
+
return if @preferences_setup_complete
|
411
|
+
|
412
|
+
java_import "android.preference.PreferenceScreen"
|
413
|
+
java_import "android.preference.Preference"
|
414
|
+
java_import "org.ruboto.RubotoPreferenceActivity"
|
415
|
+
ruboto_configure_activity(RubotoPreferenceActivity)
|
416
|
+
|
417
|
+
|
418
|
+
RubotoPreferenceActivity.class_eval do
|
419
|
+
def preference_screen(params={})
|
420
|
+
rv = self.getPreferenceManager.createPreferenceScreen(self)
|
421
|
+
rv.configure self, params
|
422
|
+
@parent.addPreference(rv) if @parent
|
423
|
+
if block_given?
|
424
|
+
old_parent, @parent = @parent, rv
|
425
|
+
yield
|
426
|
+
@parent = old_parent
|
427
|
+
end
|
428
|
+
rv
|
429
|
+
end
|
430
|
+
|
431
|
+
def setup_preference_screen &block
|
432
|
+
@preference_screen_block = block
|
433
|
+
end
|
434
|
+
|
435
|
+
def on_create(bundle)
|
436
|
+
@parent = nil
|
437
|
+
setPreferenceScreen(instance_eval &@preference_screen_block) if @preference_screen_block
|
438
|
+
instance_eval {@finish_create_block.call} if @finish_create_block
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
Preference.class_eval do
|
443
|
+
def configure(context, params = {})
|
444
|
+
params.each do |k, v|
|
445
|
+
if v.is_a?(Array)
|
446
|
+
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", *v)
|
447
|
+
else
|
448
|
+
self.send("set#{k.to_s.gsub(/(^|_)([a-z])/) {$2.upcase}}", v)
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
@preferences_setup_complete = true
|
455
|
+
end
|
456
|
+
|